|  | @@ -37,6 +37,7 @@
 | 
	
		
			
				|  |  |  #include <grpc/support/log.h>
 | 
	
		
			
				|  |  |  #include <string.h>
 | 
	
		
			
				|  |  |  #include "src/core/lib/profiling/timers.h"
 | 
	
		
			
				|  |  | +#include "src/core/lib/security/util/b64.h"
 | 
	
		
			
				|  |  |  #include "src/core/lib/slice/percent_encoding.h"
 | 
	
		
			
				|  |  |  #include "src/core/lib/slice/slice_internal.h"
 | 
	
		
			
				|  |  |  #include "src/core/lib/slice/slice_string_helpers.h"
 | 
	
	
		
			
				|  | @@ -51,8 +52,8 @@ typedef struct call_data {
 | 
	
		
			
				|  |  |    grpc_linked_mdelem status;
 | 
	
		
			
				|  |  |    grpc_linked_mdelem content_type;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  /* did this request come with payload-bin */
 | 
	
		
			
				|  |  | -  bool seen_payload_bin;
 | 
	
		
			
				|  |  | +  /* did this request come with path query containing request payload */
 | 
	
		
			
				|  |  | +  bool seen_path_with_query;
 | 
	
		
			
				|  |  |    /* flag to ensure payload_bin is delivered only once */
 | 
	
		
			
				|  |  |    bool payload_bin_delivered;
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -61,7 +62,7 @@ typedef struct call_data {
 | 
	
		
			
				|  |  |    bool *recv_cacheable_request;
 | 
	
		
			
				|  |  |    /** Closure to call when finished with the hs_on_recv hook */
 | 
	
		
			
				|  |  |    grpc_closure *on_done_recv;
 | 
	
		
			
				|  |  | -  /** Closure to call when we retrieve read message from the payload-bin header
 | 
	
		
			
				|  |  | +  /** Closure to call when we retrieve read message from the path URI
 | 
	
		
			
				|  |  |     */
 | 
	
		
			
				|  |  |    grpc_closure *recv_message_ready;
 | 
	
		
			
				|  |  |    grpc_closure *on_complete;
 | 
	
	
		
			
				|  | @@ -205,6 +206,43 @@ static grpc_error *server_filter_incoming_metadata(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  |                grpc_error_set_str(
 | 
	
		
			
				|  |  |                    GRPC_ERROR_CREATE_FROM_STATIC_STRING("Missing header"),
 | 
	
		
			
				|  |  |                    GRPC_ERROR_STR_KEY, grpc_slice_from_static_string(":path")));
 | 
	
		
			
				|  |  | +  } else if (*calld->recv_cacheable_request == true) {
 | 
	
		
			
				|  |  | +    /* We have a cacheable request made with GET verb. The path contains the
 | 
	
		
			
				|  |  | +     * query parameter which is base64 encoded request payload. */
 | 
	
		
			
				|  |  | +    const char k_query_separator = '?';
 | 
	
		
			
				|  |  | +    grpc_slice path_slice = GRPC_MDVALUE(b->idx.named.path->md);
 | 
	
		
			
				|  |  | +    uint8_t *path_ptr = (uint8_t *)GRPC_SLICE_START_PTR(path_slice);
 | 
	
		
			
				|  |  | +    size_t path_length = GRPC_SLICE_LENGTH(path_slice);
 | 
	
		
			
				|  |  | +    /* offset of the character '?' */
 | 
	
		
			
				|  |  | +    size_t offset = 0;
 | 
	
		
			
				|  |  | +    for (offset = 0; *path_ptr != k_query_separator && offset < path_length;
 | 
	
		
			
				|  |  | +         path_ptr++, offset++)
 | 
	
		
			
				|  |  | +      ;
 | 
	
		
			
				|  |  | +    if (offset < path_length) {
 | 
	
		
			
				|  |  | +      grpc_slice query_slice =
 | 
	
		
			
				|  |  | +          grpc_slice_sub(path_slice, offset + 1, path_length);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      /* substitute path metadata with just the path (not query) */
 | 
	
		
			
				|  |  | +      grpc_mdelem mdelem_path_without_query = grpc_mdelem_from_slices(
 | 
	
		
			
				|  |  | +          exec_ctx, GRPC_MDSTR_PATH, grpc_slice_sub(path_slice, 0, offset));
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      grpc_metadata_batch_substitute(exec_ctx, b, b->idx.named.path,
 | 
	
		
			
				|  |  | +                                     mdelem_path_without_query);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      /* decode payload from query and add to the slice buffer to be returned */
 | 
	
		
			
				|  |  | +      const int k_url_safe = 1;
 | 
	
		
			
				|  |  | +      grpc_slice_buffer_add(
 | 
	
		
			
				|  |  | +          &calld->read_slice_buffer,
 | 
	
		
			
				|  |  | +          grpc_base64_decode(exec_ctx,
 | 
	
		
			
				|  |  | +                             (const char *)GRPC_SLICE_START_PTR(query_slice),
 | 
	
		
			
				|  |  | +                             k_url_safe));
 | 
	
		
			
				|  |  | +      grpc_slice_buffer_stream_init(&calld->read_stream,
 | 
	
		
			
				|  |  | +                                    &calld->read_slice_buffer, 0);
 | 
	
		
			
				|  |  | +      calld->seen_path_with_query = true;
 | 
	
		
			
				|  |  | +      grpc_slice_unref_internal(exec_ctx, query_slice);
 | 
	
		
			
				|  |  | +    } else {
 | 
	
		
			
				|  |  | +      gpr_log(GPR_ERROR, "GET request without QUERY");
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    if (b->idx.named.host != NULL && b->idx.named.authority == NULL) {
 | 
	
	
		
			
				|  | @@ -228,16 +266,6 @@ static grpc_error *server_filter_incoming_metadata(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  |              GRPC_ERROR_STR_KEY, grpc_slice_from_static_string(":authority")));
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  if (b->idx.named.grpc_payload_bin != NULL) {
 | 
	
		
			
				|  |  | -    calld->seen_payload_bin = true;
 | 
	
		
			
				|  |  | -    grpc_slice_buffer_add(&calld->read_slice_buffer,
 | 
	
		
			
				|  |  | -                          grpc_slice_ref_internal(
 | 
	
		
			
				|  |  | -                              GRPC_MDVALUE(b->idx.named.grpc_payload_bin->md)));
 | 
	
		
			
				|  |  | -    grpc_slice_buffer_stream_init(&calld->read_stream,
 | 
	
		
			
				|  |  | -                                  &calld->read_slice_buffer, 0);
 | 
	
		
			
				|  |  | -    grpc_metadata_batch_remove(exec_ctx, b, b->idx.named.grpc_payload_bin);
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |    return error;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -258,8 +286,8 @@ static void hs_on_complete(grpc_exec_ctx *exec_ctx, void *user_data,
 | 
	
		
			
				|  |  |                             grpc_error *err) {
 | 
	
		
			
				|  |  |    grpc_call_element *elem = user_data;
 | 
	
		
			
				|  |  |    call_data *calld = elem->call_data;
 | 
	
		
			
				|  |  | -  /* Call recv_message_ready if we got the payload via the header field */
 | 
	
		
			
				|  |  | -  if (calld->seen_payload_bin && calld->recv_message_ready != NULL) {
 | 
	
		
			
				|  |  | +  /* Call recv_message_ready if we got the payload via the path field */
 | 
	
		
			
				|  |  | +  if (calld->seen_path_with_query && calld->recv_message_ready != NULL) {
 | 
	
		
			
				|  |  |      *calld->pp_recv_message = calld->payload_bin_delivered
 | 
	
		
			
				|  |  |                                    ? NULL
 | 
	
		
			
				|  |  |                                    : (grpc_byte_stream *)&calld->read_stream;
 | 
	
	
		
			
				|  | @@ -274,7 +302,7 @@ static void hs_recv_message_ready(grpc_exec_ctx *exec_ctx, void *user_data,
 | 
	
		
			
				|  |  |                                    grpc_error *err) {
 | 
	
		
			
				|  |  |    grpc_call_element *elem = user_data;
 | 
	
		
			
				|  |  |    call_data *calld = elem->call_data;
 | 
	
		
			
				|  |  | -  if (calld->seen_payload_bin) {
 | 
	
		
			
				|  |  | +  if (calld->seen_path_with_query) {
 | 
	
		
			
				|  |  |      /* do nothing. This is probably a GET request, and payload will be returned
 | 
	
		
			
				|  |  |      in hs_on_complete callback. */
 | 
	
		
			
				|  |  |    } else {
 |