Merge pull request #6034 from dgquintas/uri_query_parts

Added & and = to URI queries
pull/5570/head^2
Nicolas Noble 9 years ago
commit 38d812077b
  1. 68
      src/core/lib/client_config/uri_parser.c
  2. 12
      src/core/lib/client_config/uri_parser.h
  3. 51
      test/core/client_config/uri_parser_test.c

@ -38,8 +38,12 @@
#include <grpc/support/alloc.h> #include <grpc/support/alloc.h>
#include <grpc/support/log.h> #include <grpc/support/log.h>
#include <grpc/support/port_platform.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 <grpc/support/string_util.h>
#include "src/core/lib/support/string.h"
/** a size_t default value... maps to all 1's */ /** a size_t default value... maps to all 1's */
#define NOT_SET (~(size_t)0) #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; 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 *grpc_uri_parse(const char *uri_text, int suppress_errors) {
grpc_uri *uri; grpc_uri *uri;
size_t scheme_begin = 0; 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->path = copy_component(uri_text, path_begin, path_end);
uri->query = copy_component(uri_text, query_begin, query_end); uri->query = copy_component(uri_text, query_begin, query_end);
uri->fragment = copy_component(uri_text, fragment_begin, fragment_end); uri->fragment = copy_component(uri_text, fragment_begin, fragment_end);
parse_query_parts(uri);
return 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) { void grpc_uri_destroy(grpc_uri *uri) {
if (!uri) return; if (!uri) return;
gpr_free(uri->scheme); gpr_free(uri->scheme);
gpr_free(uri->authority); gpr_free(uri->authority);
gpr_free(uri->path); gpr_free(uri->path);
gpr_free(uri->query); 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->fragment);
gpr_free(uri); gpr_free(uri);
} }

@ -34,17 +34,29 @@
#ifndef GRPC_CORE_LIB_CLIENT_CONFIG_URI_PARSER_H #ifndef GRPC_CORE_LIB_CLIENT_CONFIG_URI_PARSER_H
#define GRPC_CORE_LIB_CLIENT_CONFIG_URI_PARSER_H #define GRPC_CORE_LIB_CLIENT_CONFIG_URI_PARSER_H
#include <stddef.h>
typedef struct { typedef struct {
char *scheme; char *scheme;
char *authority; char *authority;
char *path; char *path;
char *query; char *query;
/** Query substrings separated by '&' */
char **query_parts;
/** Number of elements in \a query_parts and \a query_parts_values */
size_t num_query_parts;
/** Split each query part by '='. NULL if not present. */
char **query_parts_values;
char *fragment; char *fragment;
} grpc_uri; } grpc_uri;
/** parse a uri, return NULL on failure */ /** parse a uri, return NULL on failure */
grpc_uri *grpc_uri_parse(const char *uri_text, int suppress_errors); grpc_uri *grpc_uri_parse(const char *uri_text, int suppress_errors);
/** return the part of a query string after the '=' in "?key=xxx&...", or NULL
* if key is not present */
const char *grpc_uri_get_query_arg(const grpc_uri *uri, const char *key);
/** destroy a uri */ /** destroy a uri */
void grpc_uri_destroy(grpc_uri *uri); void grpc_uri_destroy(grpc_uri *uri);

@ -56,6 +56,56 @@ static void test_fails(const char *uri_text) {
GPR_ASSERT(NULL == grpc_uri_parse(uri_text, 0)); GPR_ASSERT(NULL == grpc_uri_parse(uri_text, 0));
} }
static void test_query_parts() {
{
const char *uri_text = "http://foo/path?a&b=B&c=&#frag";
grpc_uri *uri = grpc_uri_parse(uri_text, 0);
GPR_ASSERT(uri);
GPR_ASSERT(0 == strcmp("http", uri->scheme));
GPR_ASSERT(0 == strcmp("foo", uri->authority));
GPR_ASSERT(0 == strcmp("/path", uri->path));
GPR_ASSERT(0 == strcmp("a&b=B&c=&", uri->query));
GPR_ASSERT(4 == uri->num_query_parts);
GPR_ASSERT(0 == strcmp("a", uri->query_parts[0]));
GPR_ASSERT(NULL == uri->query_parts_values[0]);
GPR_ASSERT(0 == strcmp("b", uri->query_parts[1]));
GPR_ASSERT(0 == strcmp("B", uri->query_parts_values[1]));
GPR_ASSERT(0 == strcmp("c", uri->query_parts[2]));
GPR_ASSERT(0 == strcmp("", uri->query_parts_values[2]));
GPR_ASSERT(0 == strcmp("", uri->query_parts[3]));
GPR_ASSERT(NULL == uri->query_parts_values[3]);
GPR_ASSERT(NULL == grpc_uri_get_query_arg(uri, "a"));
GPR_ASSERT(0 == strcmp("B", grpc_uri_get_query_arg(uri, "b")));
GPR_ASSERT(0 == strcmp("", grpc_uri_get_query_arg(uri, "c")));
GPR_ASSERT(NULL == grpc_uri_get_query_arg(uri, ""));
GPR_ASSERT(0 == strcmp("frag", uri->fragment));
grpc_uri_destroy(uri);
}
{
/* empty query */
const char *uri_text = "http://foo/path";
grpc_uri *uri = grpc_uri_parse(uri_text, 0);
GPR_ASSERT(uri);
GPR_ASSERT(0 == strcmp("http", uri->scheme));
GPR_ASSERT(0 == strcmp("foo", uri->authority));
GPR_ASSERT(0 == strcmp("/path", uri->path));
GPR_ASSERT(0 == strcmp("", uri->query));
GPR_ASSERT(0 == uri->num_query_parts);
GPR_ASSERT(NULL == uri->query_parts);
GPR_ASSERT(NULL == uri->query_parts_values);
GPR_ASSERT(0 == strcmp("", uri->fragment));
grpc_uri_destroy(uri);
}
}
int main(int argc, char **argv) { int main(int argc, char **argv) {
grpc_test_init(argc, argv); grpc_test_init(argc, argv);
test_succeeds("http://www.google.com", "http", "www.google.com", "", "", ""); test_succeeds("http://www.google.com", "http", "www.google.com", "", "", "");
@ -82,5 +132,6 @@ int main(int argc, char **argv) {
test_fails("http://foo?x[bar]"); test_fails("http://foo?x[bar]");
test_fails("http://foo?bar#lol#"); test_fails("http://foo?bar#lol#");
test_query_parts();
return 0; return 0;
} }

Loading…
Cancel
Save