aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar David Garcia Quintas <dgq@google.com>2015-09-07 11:28:58 -0700
committerGravatar David Garcia Quintas <dgq@google.com>2015-09-08 16:21:44 -0700
commit526789159c00221aaaeb3b02b5add70b5c5fcb6d (patch)
treecee186617d488413073d427a63c4472dfbe4d3eb /src
parent02128e9bbf92c3900f0927a724482b5b3ff7541f (diff)
Added queries and fragments to uri parser
Diffstat (limited to 'src')
-rw-r--r--src/core/client_config/uri_parser.c127
-rw-r--r--src/core/client_config/uri_parser.h2
2 files changed, 113 insertions, 16 deletions
diff --git a/src/core/client_config/uri_parser.c b/src/core/client_config/uri_parser.c
index 410a61c8cf..36ecfa5e8e 100644
--- a/src/core/client_config/uri_parser.c
+++ b/src/core/client_config/uri_parser.c
@@ -60,13 +60,80 @@ static grpc_uri *bad_uri(const char *uri_text, int pos, const char *section,
return NULL;
}
-static char *copy_fragment(const char *src, int begin, int end) {
+/** Returns a copy of \a src[begin, end) */
+static char *copy_component(const char *src, int begin, int end) {
char *out = gpr_malloc(end - begin + 1);
memcpy(out, src + begin, end - begin);
out[end - begin] = 0;
return out;
}
+/** Returns how many chars to advance if \a uri_text[i] begins a valid \a pchar
+ * production. If \a uri_text[i] introduces an invalid \a pchar (such as percent
+ * sign not followed by two hex digits), -1 is returned. */
+static int parse_pchar(const char *uri_text, int i) {
+ /* pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
+ * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
+ * pct-encoded = "%" HEXDIG HEXDIG
+ * sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
+ / "*" / "+" / "," / ";" / "=" */
+ char c = uri_text[i];
+ if ( ((c >= 'A') && (c <= 'Z')) ||
+ ((c >= 'a') && (c <= 'z')) ||
+ ((c >= '0') && (c <= '9')) ||
+ (c == '-' || c == '.' || c == '_' || c == '~') || /* unreserved */
+
+ (c == '!' || c == '$' || c == '&' || c == '\'' || c == '$' || c == '&' ||
+ c == '(' || c == ')' || c == '*' || c == '+' || c == ',' || c == ';' ||
+ c == '=') /* sub-delims */ ) {
+ return 1;
+ }
+ if (c == '%') { /* pct-encoded */
+ int j;
+ if (uri_text[i+1] == 0 || uri_text[i+2] == 0) {
+ return -1;
+ }
+ for (j = i + 1; j < 2; j++) {
+ c = uri_text[j];
+ if (!(((c >= '0') && (c <= '9')) ||
+ ((c >= 'a') && (c <= 'f')) ||
+ ((c >= 'A') && (c <= 'F')))) {
+ return -1;
+ }
+ }
+ return 2;
+ }
+ return 0;
+}
+
+/* *( pchar / "?" / "/" ) */
+static int parse_query(const char *uri_text, int i) {
+ char c;
+ while ((c = uri_text[i]) != 0) {
+ const int advance = parse_pchar(uri_text, i); /* pchar */
+ switch (advance) {
+ case 0: /* uri_text[i] isn't in pchar */
+ /* maybe it's ? or / */
+ if (uri_text[i] == '?' || uri_text[i] == '/') {
+ i++;
+ break;
+ } else {
+ return i;
+ }
+ case 1:
+ case 2:
+ i += advance;
+ break;
+ default: /* uri_text[i] introduces an invalid URI */
+ return -i;
+ }
+ }
+ return i; /* first uri_text position past the \a query production, maybe \0 */
+}
+
+/* alias for consistency */
+static int (*parse_fragment)(const char *uri_text, int i) = parse_query;
+
grpc_uri *grpc_uri_parse(const char *uri_text, int suppress_errors) {
grpc_uri *uri;
int scheme_begin = 0;
@@ -75,6 +142,10 @@ grpc_uri *grpc_uri_parse(const char *uri_text, int suppress_errors) {
int authority_end = -1;
int path_begin = -1;
int path_end = -1;
+ int query_begin = -1;
+ int query_end = -1;
+ int fragment_begin = -1;
+ int fragment_end = -1;
int i;
for (i = scheme_begin; uri_text[i] != 0; i++) {
@@ -99,15 +170,9 @@ grpc_uri *grpc_uri_parse(const char *uri_text, int suppress_errors) {
if (uri_text[scheme_end + 1] == '/' && uri_text[scheme_end + 2] == '/') {
authority_begin = scheme_end + 3;
for (i = authority_begin; uri_text[i] != 0 && authority_end == -1; i++) {
- if (uri_text[i] == '/') {
+ if (uri_text[i] == '/' || uri_text[i] == '?' || uri_text[i] == '#') {
authority_end = i;
}
- if (uri_text[i] == '?') {
- return bad_uri(uri_text, i, "query_not_supported", suppress_errors);
- }
- if (uri_text[i] == '#') {
- return bad_uri(uri_text, i, "fragment_not_supported", suppress_errors);
- }
}
if (authority_end == -1 && uri_text[i] == 0) {
authority_end = i;
@@ -122,20 +187,48 @@ grpc_uri *grpc_uri_parse(const char *uri_text, int suppress_errors) {
}
for (i = path_begin; uri_text[i] != 0; i++) {
- if (uri_text[i] == '?') {
- return bad_uri(uri_text, i, "query_not_supported", suppress_errors);
+ if (uri_text[i] == '?' || uri_text[i] == '#') {
+ path_end = i;
+ break;
}
- if (uri_text[i] == '#') {
- return bad_uri(uri_text, i, "fragment_not_supported", suppress_errors);
+ }
+ if (path_end == -1 && uri_text[i] == 0) {
+ path_end = i;
+ }
+ if (path_end == -1) {
+ return bad_uri(uri_text, i, "path", suppress_errors);
+ }
+
+ if (uri_text[i] == '?') {
+ query_begin = i + 1;
+ i = parse_query(uri_text, query_begin);
+ if (i < 0) {
+ return bad_uri(uri_text, -i, "query", suppress_errors);
+ } else if (uri_text[i] != 0 && uri_text[i] != '#') {
+ /* We must be at the end or at the beginning of a fragment */
+ return bad_uri(uri_text, i, "query", suppress_errors);
+ }
+ query_end = i;
+ }
+ if (uri_text[i] == '#') {
+ fragment_begin = i + 1;
+ i = parse_fragment(uri_text, fragment_begin);
+ if (i < 0) {
+ return bad_uri(uri_text, i - fragment_end, "fragment", suppress_errors);
+ } else if (uri_text[i] != 0) {
+ /* We must be at the end */
+ return bad_uri(uri_text, i, "fragment", suppress_errors);
}
+ fragment_end = i;
}
- path_end = i;
uri = gpr_malloc(sizeof(*uri));
memset(uri, 0, sizeof(*uri));
- uri->scheme = copy_fragment(uri_text, scheme_begin, scheme_end);
- uri->authority = copy_fragment(uri_text, authority_begin, authority_end);
- uri->path = copy_fragment(uri_text, path_begin, path_end);
+ uri->scheme = copy_component(uri_text, scheme_begin, scheme_end);
+ uri->authority = copy_component(uri_text, authority_begin, authority_end);
+ 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);
return uri;
}
@@ -145,5 +238,7 @@ void grpc_uri_destroy(grpc_uri *uri) {
gpr_free(uri->scheme);
gpr_free(uri->authority);
gpr_free(uri->path);
+ gpr_free(uri->query);
+ gpr_free(uri->fragment);
gpr_free(uri);
}
diff --git a/src/core/client_config/uri_parser.h b/src/core/client_config/uri_parser.h
index ce4e6aecb0..b8daa13bd4 100644
--- a/src/core/client_config/uri_parser.h
+++ b/src/core/client_config/uri_parser.h
@@ -38,6 +38,8 @@ typedef struct {
char *scheme;
char *authority;
char *path;
+ char *query;
+ char *fragment;
} grpc_uri;
/** parse a uri, return NULL on failure */