|
|
@ -38,11 +38,12 @@ |
|
|
|
/** 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) |
|
|
|
|
|
|
|
|
|
|
|
static grpc_uri* bad_uri(const char* uri_text, size_t pos, const char* section, |
|
|
|
static grpc_uri* bad_uri(absl::string_view uri_text, size_t pos, |
|
|
|
bool suppress_errors) { |
|
|
|
const char* section, bool suppress_errors) { |
|
|
|
if (!suppress_errors) { |
|
|
|
if (!suppress_errors) { |
|
|
|
std::string line_prefix = absl::StrFormat("bad uri.%s: '", section); |
|
|
|
std::string line_prefix = absl::StrFormat("bad uri.%s: '", section); |
|
|
|
gpr_log(GPR_ERROR, "%s%s'", line_prefix.c_str(), uri_text); |
|
|
|
gpr_log(GPR_ERROR, "%s%s'", line_prefix.c_str(), |
|
|
|
|
|
|
|
std::string(uri_text).c_str()); |
|
|
|
size_t pfx_len = line_prefix.size() + pos; |
|
|
|
size_t pfx_len = line_prefix.size() + pos; |
|
|
|
gpr_log(GPR_ERROR, "%s^ here", std::string(pfx_len, ' ').c_str()); |
|
|
|
gpr_log(GPR_ERROR, "%s^ here", std::string(pfx_len, ' ').c_str()); |
|
|
|
} |
|
|
|
} |
|
|
@ -50,12 +51,12 @@ static grpc_uri* bad_uri(const char* uri_text, size_t pos, const char* section, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** Returns a copy of percent decoded \a src[begin, end) */ |
|
|
|
/** Returns a copy of percent decoded \a src[begin, end) */ |
|
|
|
static char* decode_and_copy_component(const char* src, size_t begin, |
|
|
|
static char* decode_and_copy_component(absl::string_view src, size_t begin, |
|
|
|
size_t end) { |
|
|
|
size_t end) { |
|
|
|
grpc_slice component = |
|
|
|
grpc_slice component = |
|
|
|
(begin == NOT_SET || end == NOT_SET) |
|
|
|
(begin == NOT_SET || end == NOT_SET) |
|
|
|
? grpc_empty_slice() |
|
|
|
? grpc_empty_slice() |
|
|
|
: grpc_slice_from_copied_buffer(src + begin, end - begin); |
|
|
|
: grpc_slice_from_copied_buffer(src.data() + begin, end - begin); |
|
|
|
grpc_slice decoded_component = |
|
|
|
grpc_slice decoded_component = |
|
|
|
grpc_permissive_percent_decode_slice(component); |
|
|
|
grpc_permissive_percent_decode_slice(component); |
|
|
|
char* out = grpc_dump_slice(decoded_component, GPR_DUMP_ASCII); |
|
|
|
char* out = grpc_dump_slice(decoded_component, GPR_DUMP_ASCII); |
|
|
@ -72,7 +73,7 @@ static bool valid_hex(char c) { |
|
|
|
/** Returns how many chars to advance if \a uri_text[i] begins a valid \a pchar
|
|
|
|
/** 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 |
|
|
|
* production. If \a uri_text[i] introduces an invalid \a pchar (such as percent |
|
|
|
* sign not followed by two hex digits), NOT_SET is returned. */ |
|
|
|
* sign not followed by two hex digits), NOT_SET is returned. */ |
|
|
|
static size_t parse_pchar(const char* uri_text, size_t i) { |
|
|
|
static size_t parse_pchar(absl::string_view uri_text, size_t i) { |
|
|
|
/* pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
|
|
|
|
/* pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
|
|
|
|
* unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" |
|
|
|
* unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" |
|
|
|
* pct-encoded = "%" HEXDIG HEXDIG |
|
|
|
* pct-encoded = "%" HEXDIG HEXDIG |
|
|
@ -105,7 +106,8 @@ static size_t parse_pchar(const char* uri_text, size_t i) { |
|
|
|
case '=': |
|
|
|
case '=': |
|
|
|
return 1; |
|
|
|
return 1; |
|
|
|
case '%': /* pct-encoded */ |
|
|
|
case '%': /* pct-encoded */ |
|
|
|
if (valid_hex(uri_text[i + 1]) && valid_hex(uri_text[i + 2])) { |
|
|
|
if (uri_text.size() > i + 2 && valid_hex(uri_text[i + 1]) && |
|
|
|
|
|
|
|
valid_hex(uri_text[i + 2])) { |
|
|
|
return 2; |
|
|
|
return 2; |
|
|
|
} |
|
|
|
} |
|
|
|
return NOT_SET; |
|
|
|
return NOT_SET; |
|
|
@ -114,9 +116,8 @@ static size_t parse_pchar(const char* uri_text, size_t i) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* *( pchar / "?" / "/" ) */ |
|
|
|
/* *( pchar / "?" / "/" ) */ |
|
|
|
static int parse_fragment_or_query(const char* uri_text, size_t* i) { |
|
|
|
static int parse_fragment_or_query(absl::string_view uri_text, size_t* i) { |
|
|
|
char c; |
|
|
|
while (uri_text.size() > *i) { |
|
|
|
while ((c = uri_text[*i]) != 0) { |
|
|
|
|
|
|
|
const size_t advance = parse_pchar(uri_text, *i); /* pchar */ |
|
|
|
const size_t advance = parse_pchar(uri_text, *i); /* pchar */ |
|
|
|
switch (advance) { |
|
|
|
switch (advance) { |
|
|
|
case 0: /* uri_text[i] isn't in pchar */ |
|
|
|
case 0: /* uri_text[i] isn't in pchar */ |
|
|
@ -178,7 +179,7 @@ static void parse_query_parts(grpc_uri* uri) { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
grpc_uri* grpc_uri_parse(const char* uri_text, bool suppress_errors) { |
|
|
|
grpc_uri* grpc_uri_parse(absl::string_view uri_text, bool suppress_errors) { |
|
|
|
grpc_uri* uri; |
|
|
|
grpc_uri* uri; |
|
|
|
size_t scheme_begin = 0; |
|
|
|
size_t scheme_begin = 0; |
|
|
|
size_t scheme_end = NOT_SET; |
|
|
|
size_t scheme_end = NOT_SET; |
|
|
@ -192,7 +193,7 @@ grpc_uri* grpc_uri_parse(const char* uri_text, bool suppress_errors) { |
|
|
|
size_t fragment_end = NOT_SET; |
|
|
|
size_t fragment_end = NOT_SET; |
|
|
|
size_t i; |
|
|
|
size_t i; |
|
|
|
|
|
|
|
|
|
|
|
for (i = scheme_begin; uri_text[i] != 0; i++) { |
|
|
|
for (i = scheme_begin; i < uri_text.size(); ++i) { |
|
|
|
if (uri_text[i] == ':') { |
|
|
|
if (uri_text[i] == ':') { |
|
|
|
scheme_end = i; |
|
|
|
scheme_end = i; |
|
|
|
break; |
|
|
|
break; |
|
|
@ -211,15 +212,16 @@ grpc_uri* grpc_uri_parse(const char* uri_text, bool suppress_errors) { |
|
|
|
return bad_uri(uri_text, i, "scheme", suppress_errors); |
|
|
|
return bad_uri(uri_text, i, "scheme", suppress_errors); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (uri_text[scheme_end + 1] == '/' && uri_text[scheme_end + 2] == '/') { |
|
|
|
if (uri_text.size() > scheme_end + 2 && uri_text[scheme_end + 1] == '/' && |
|
|
|
|
|
|
|
uri_text[scheme_end + 2] == '/') { |
|
|
|
authority_begin = scheme_end + 3; |
|
|
|
authority_begin = scheme_end + 3; |
|
|
|
for (i = authority_begin; uri_text[i] != 0 && authority_end == NOT_SET; |
|
|
|
for (i = authority_begin; uri_text.size() > i && authority_end == NOT_SET; |
|
|
|
i++) { |
|
|
|
i++) { |
|
|
|
if (uri_text[i] == '/' || uri_text[i] == '?' || uri_text[i] == '#') { |
|
|
|
if (uri_text[i] == '/' || uri_text[i] == '?' || uri_text[i] == '#') { |
|
|
|
authority_end = i; |
|
|
|
authority_end = i; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
if (authority_end == NOT_SET && uri_text[i] == 0) { |
|
|
|
if (authority_end == NOT_SET && uri_text.size() == i) { |
|
|
|
authority_end = i; |
|
|
|
authority_end = i; |
|
|
|
} |
|
|
|
} |
|
|
|
if (authority_end == NOT_SET) { |
|
|
|
if (authority_end == NOT_SET) { |
|
|
@ -231,34 +233,34 @@ grpc_uri* grpc_uri_parse(const char* uri_text, bool suppress_errors) { |
|
|
|
path_begin = scheme_end + 1; |
|
|
|
path_begin = scheme_end + 1; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
for (i = path_begin; uri_text[i] != 0; i++) { |
|
|
|
for (i = path_begin; i < uri_text.size(); ++i) { |
|
|
|
if (uri_text[i] == '?' || uri_text[i] == '#') { |
|
|
|
if (uri_text[i] == '?' || uri_text[i] == '#') { |
|
|
|
path_end = i; |
|
|
|
path_end = i; |
|
|
|
break; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
if (path_end == NOT_SET && uri_text[i] == 0) { |
|
|
|
if (path_end == NOT_SET && uri_text.size() == i) { |
|
|
|
path_end = i; |
|
|
|
path_end = i; |
|
|
|
} |
|
|
|
} |
|
|
|
if (path_end == NOT_SET) { |
|
|
|
if (path_end == NOT_SET) { |
|
|
|
return bad_uri(uri_text, i, "path", suppress_errors); |
|
|
|
return bad_uri(uri_text, i, "path", suppress_errors); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (uri_text[i] == '?') { |
|
|
|
if (uri_text.size() > i && uri_text[i] == '?') { |
|
|
|
query_begin = ++i; |
|
|
|
query_begin = ++i; |
|
|
|
if (!parse_fragment_or_query(uri_text, &i)) { |
|
|
|
if (!parse_fragment_or_query(uri_text, &i)) { |
|
|
|
return bad_uri(uri_text, i, "query", suppress_errors); |
|
|
|
return bad_uri(uri_text, i, "query", suppress_errors); |
|
|
|
} else if (uri_text[i] != 0 && uri_text[i] != '#') { |
|
|
|
} else if (uri_text.size() > i && uri_text[i] != '#') { |
|
|
|
/* We must be at the end or at the beginning of a fragment */ |
|
|
|
/* We must be at the end or at the beginning of a fragment */ |
|
|
|
return bad_uri(uri_text, i, "query", suppress_errors); |
|
|
|
return bad_uri(uri_text, i, "query", suppress_errors); |
|
|
|
} |
|
|
|
} |
|
|
|
query_end = i; |
|
|
|
query_end = i; |
|
|
|
} |
|
|
|
} |
|
|
|
if (uri_text[i] == '#') { |
|
|
|
if (uri_text.size() > i && uri_text[i] == '#') { |
|
|
|
fragment_begin = ++i; |
|
|
|
fragment_begin = ++i; |
|
|
|
if (!parse_fragment_or_query(uri_text, &i)) { |
|
|
|
if (!parse_fragment_or_query(uri_text, &i)) { |
|
|
|
return bad_uri(uri_text, i - fragment_end, "fragment", suppress_errors); |
|
|
|
return bad_uri(uri_text, i - fragment_end, "fragment", suppress_errors); |
|
|
|
} else if (uri_text[i] != 0) { |
|
|
|
} else if (uri_text.size() > i) { |
|
|
|
/* We must be at the end */ |
|
|
|
/* We must be at the end */ |
|
|
|
return bad_uri(uri_text, i, "fragment", suppress_errors); |
|
|
|
return bad_uri(uri_text, i, "fragment", suppress_errors); |
|
|
|
} |
|
|
|
} |
|
|
|