|  | @@ -38,8 +38,12 @@
 | 
	
		
			
				|  |  |  #include <grpc/support/alloc.h>
 | 
	
		
			
				|  |  |  #include <grpc/support/log.h>
 | 
	
		
			
				|  |  |  #include <grpc/support/port_platform.h>
 | 
	
		
			
				|  |  | +#include <grpc/support/slice.h>
 | 
	
		
			
				|  |  | +#include <grpc/support/slice_buffer.h>
 | 
	
		
			
				|  |  |  #include <grpc/support/string_util.h>
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +#include "src/core/lib/support/string.h"
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  /** a size_t default value... maps to all 1's */
 | 
	
		
			
				|  |  |  #define NOT_SET (~(size_t)0)
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -133,6 +137,51 @@ static int parse_fragment_or_query(const char *uri_text, size_t *i) {
 | 
	
		
			
				|  |  |    return 1;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +static void do_nothing(void *ignored) {}
 | 
	
		
			
				|  |  | +static void parse_query_parts(grpc_uri *uri) {
 | 
	
		
			
				|  |  | +  static const char *QUERY_PARTS_SEPARATOR = "&";
 | 
	
		
			
				|  |  | +  static const char *QUERY_PARTS_VALUE_SEPARATOR = "=";
 | 
	
		
			
				|  |  | +  GPR_ASSERT(uri->query != NULL);
 | 
	
		
			
				|  |  | +  if (uri->query[0] == '\0') {
 | 
	
		
			
				|  |  | +    uri->query_parts = NULL;
 | 
	
		
			
				|  |  | +    uri->query_parts_values = NULL;
 | 
	
		
			
				|  |  | +    uri->num_query_parts = 0;
 | 
	
		
			
				|  |  | +    return;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  gpr_slice query_slice =
 | 
	
		
			
				|  |  | +      gpr_slice_new(uri->query, strlen(uri->query), do_nothing);
 | 
	
		
			
				|  |  | +  gpr_slice_buffer query_parts; /* the &-separated elements of the query */
 | 
	
		
			
				|  |  | +  gpr_slice_buffer query_param_parts; /* the =-separated subelements */
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  gpr_slice_buffer_init(&query_parts);
 | 
	
		
			
				|  |  | +  gpr_slice_buffer_init(&query_param_parts);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  gpr_slice_split(query_slice, QUERY_PARTS_SEPARATOR, &query_parts);
 | 
	
		
			
				|  |  | +  uri->query_parts = gpr_malloc(query_parts.count * sizeof(char *));
 | 
	
		
			
				|  |  | +  uri->query_parts_values = gpr_malloc(query_parts.count * sizeof(char *));
 | 
	
		
			
				|  |  | +  uri->num_query_parts = query_parts.count;
 | 
	
		
			
				|  |  | +  for (size_t i = 0; i < query_parts.count; i++) {
 | 
	
		
			
				|  |  | +    gpr_slice_split(query_parts.slices[i], QUERY_PARTS_VALUE_SEPARATOR,
 | 
	
		
			
				|  |  | +                    &query_param_parts);
 | 
	
		
			
				|  |  | +    GPR_ASSERT(query_param_parts.count > 0);
 | 
	
		
			
				|  |  | +    uri->query_parts[i] =
 | 
	
		
			
				|  |  | +        gpr_dump_slice(query_param_parts.slices[0], GPR_DUMP_ASCII);
 | 
	
		
			
				|  |  | +    if (query_param_parts.count > 1) {
 | 
	
		
			
				|  |  | +      /* TODO(dgq): only the first value after the separator is considered.
 | 
	
		
			
				|  |  | +       * Perhaps all chars after the first separator for the query part should
 | 
	
		
			
				|  |  | +       * be included, even if they include the separator. */
 | 
	
		
			
				|  |  | +      uri->query_parts_values[i] =
 | 
	
		
			
				|  |  | +          gpr_dump_slice(query_param_parts.slices[1], GPR_DUMP_ASCII);
 | 
	
		
			
				|  |  | +    } else {
 | 
	
		
			
				|  |  | +      uri->query_parts_values[i] = NULL;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    gpr_slice_buffer_reset_and_unref(&query_param_parts);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  gpr_slice_buffer_destroy(&query_parts);
 | 
	
		
			
				|  |  | +  gpr_slice_buffer_destroy(&query_param_parts);
 | 
	
		
			
				|  |  | +  gpr_slice_unref(query_slice);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  grpc_uri *grpc_uri_parse(const char *uri_text, int suppress_errors) {
 | 
	
		
			
				|  |  |    grpc_uri *uri;
 | 
	
		
			
				|  |  |    size_t scheme_begin = 0;
 | 
	
	
		
			
				|  | @@ -227,16 +276,35 @@ grpc_uri *grpc_uri_parse(const char *uri_text, int suppress_errors) {
 | 
	
		
			
				|  |  |    uri->path = copy_component(uri_text, path_begin, path_end);
 | 
	
		
			
				|  |  |    uri->query = copy_component(uri_text, query_begin, query_end);
 | 
	
		
			
				|  |  |    uri->fragment = copy_component(uri_text, fragment_begin, fragment_end);
 | 
	
		
			
				|  |  | +  parse_query_parts(uri);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    return uri;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +const char *grpc_uri_get_query_arg(const grpc_uri *uri, const char *key) {
 | 
	
		
			
				|  |  | +  GPR_ASSERT(key != NULL);
 | 
	
		
			
				|  |  | +  if (key[0] == '\0') return NULL;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  for (size_t i = 0; i < uri->num_query_parts; ++i) {
 | 
	
		
			
				|  |  | +    if (0 == strcmp(key, uri->query_parts[i])) {
 | 
	
		
			
				|  |  | +      return uri->query_parts_values[i];
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  return NULL;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  void grpc_uri_destroy(grpc_uri *uri) {
 | 
	
		
			
				|  |  |    if (!uri) return;
 | 
	
		
			
				|  |  |    gpr_free(uri->scheme);
 | 
	
		
			
				|  |  |    gpr_free(uri->authority);
 | 
	
		
			
				|  |  |    gpr_free(uri->path);
 | 
	
		
			
				|  |  |    gpr_free(uri->query);
 | 
	
		
			
				|  |  | +  for (size_t i = 0; i < uri->num_query_parts; ++i) {
 | 
	
		
			
				|  |  | +    gpr_free(uri->query_parts[i]);
 | 
	
		
			
				|  |  | +    gpr_free(uri->query_parts_values[i]);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  gpr_free(uri->query_parts);
 | 
	
		
			
				|  |  | +  gpr_free(uri->query_parts_values);
 | 
	
		
			
				|  |  |    gpr_free(uri->fragment);
 | 
	
		
			
				|  |  |    gpr_free(uri);
 | 
	
		
			
				|  |  |  }
 |