aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-rw-r--r--src/core/channel/compress_filter.c37
-rw-r--r--src/core/client_config/uri_parser.c130
-rw-r--r--src/core/client_config/uri_parser.h2
-rw-r--r--src/core/compression/algorithm.c23
-rw-r--r--src/core/surface/call.c2
5 files changed, 168 insertions, 26 deletions
diff --git a/src/core/channel/compress_filter.c b/src/core/channel/compress_filter.c
index 17b48f31c1..7959603102 100644
--- a/src/core/channel/compress_filter.c
+++ b/src/core/channel/compress_filter.c
@@ -71,6 +71,8 @@ typedef struct channel_data {
grpc_mdelem *mdelem_accept_encoding;
/** The default, channel-level, compression algorithm */
grpc_compression_algorithm default_compression_algorithm;
+ /** Compression options for the channel */
+ grpc_compression_options compression_options;
} channel_data;
/** Compress \a slices in place using \a algorithm. Returns 1 if compression did
@@ -103,7 +105,17 @@ static grpc_mdelem *compression_md_filter(void *user_data, grpc_mdelem *md) {
const char *md_c_str = grpc_mdstr_as_c_string(md->value);
if (!grpc_compression_algorithm_parse(md_c_str, strlen(md_c_str),
&calld->compression_algorithm)) {
- gpr_log(GPR_ERROR, "Invalid compression algorithm: '%s'. Ignoring.",
+ gpr_log(GPR_ERROR,
+ "Invalid compression algorithm: '%s' (unknown). Ignoring.",
+ md_c_str);
+ calld->compression_algorithm = GRPC_COMPRESS_NONE;
+ }
+ if (grpc_compression_options_is_algorithm_enabled(
+ &channeld->compression_options, calld->compression_algorithm) ==
+ 0) {
+ gpr_log(GPR_ERROR,
+ "Invalid compression algorithm: '%s' (previously disabled). "
+ "Ignoring.",
md_c_str);
calld->compression_algorithm = GRPC_COMPRESS_NONE;
}
@@ -299,11 +311,21 @@ static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master,
channel_data *channeld = elem->channel_data;
grpc_compression_algorithm algo_idx;
const char *supported_algorithms_names[GRPC_COMPRESS_ALGORITHMS_COUNT - 1];
+ size_t supported_algorithms_idx = 0;
char *accept_encoding_str;
size_t accept_encoding_str_len;
+ grpc_compression_options_init(&channeld->compression_options);
+ channeld->compression_options.enabled_algorithms_bitset =
+ (gpr_uint32)grpc_channel_args_compression_algorithm_get_states(args);
+
channeld->default_compression_algorithm =
grpc_channel_args_get_compression_algorithm(args);
+ /* Make sure the default isn't disabled. */
+ GPR_ASSERT(grpc_compression_options_is_algorithm_enabled(
+ &channeld->compression_options, channeld->default_compression_algorithm));
+ channeld->compression_options.default_compression_algorithm =
+ channeld->default_compression_algorithm;
channeld->mdstr_request_compression_algorithm_key =
grpc_mdstr_from_string(mdctx, GRPC_COMPRESS_REQUEST_ALGORITHM_KEY, 0);
@@ -316,6 +338,11 @@ static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master,
for (algo_idx = 0; algo_idx < GRPC_COMPRESS_ALGORITHMS_COUNT; ++algo_idx) {
char *algorithm_name;
+ /* skip disabled algorithms */
+ if (grpc_compression_options_is_algorithm_enabled(
+ &channeld->compression_options, algo_idx) == 0) {
+ continue;
+ }
GPR_ASSERT(grpc_compression_algorithm_name(algo_idx, &algorithm_name) != 0);
channeld->mdelem_compression_algorithms[algo_idx] =
grpc_mdelem_from_metadata_strings(
@@ -323,15 +350,15 @@ static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master,
GRPC_MDSTR_REF(channeld->mdstr_outgoing_compression_algorithm_key),
grpc_mdstr_from_string(mdctx, algorithm_name, 0));
if (algo_idx > 0) {
- supported_algorithms_names[algo_idx - 1] = algorithm_name;
+ supported_algorithms_names[supported_algorithms_idx++] = algorithm_name;
}
}
/* TODO(dgq): gpr_strjoin_sep could be made to work with statically allocated
* arrays, as to avoid the heap allocs */
- accept_encoding_str = gpr_strjoin_sep(
- supported_algorithms_names, GPR_ARRAY_SIZE(supported_algorithms_names),
- ", ", &accept_encoding_str_len);
+ accept_encoding_str =
+ gpr_strjoin_sep(supported_algorithms_names, supported_algorithms_idx, ",",
+ &accept_encoding_str_len);
channeld->mdelem_accept_encoding = grpc_mdelem_from_metadata_strings(
mdctx, GRPC_MDSTR_REF(channeld->mdstr_compression_capabilities_key),
diff --git a/src/core/client_config/uri_parser.c b/src/core/client_config/uri_parser.c
index 5c2aa46e53..2738e2df57 100644
--- a/src/core/client_config/uri_parser.c
+++ b/src/core/client_config/uri_parser.c
@@ -39,6 +39,9 @@
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
+/** a size_t default value... maps to all 1's */
+#define NOT_SET (~(size_t)0)
+
static grpc_uri *bad_uri(const char *uri_text, size_t pos, const char *section,
int suppress_errors) {
char *line_prefix;
@@ -60,24 +63,89 @@ static grpc_uri *bad_uri(const char *uri_text, size_t pos, const char *section,
return NULL;
}
-static char *copy_fragment(const char *src, size_t begin, size_t end) {
- char *out;
- GPR_ASSERT(end >= begin);
- out = gpr_malloc(end - begin + 1);
+/** Returns a copy of \a src[begin, end) */
+static char *copy_component(const char *src, size_t begin, size_t 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), NOT_SET is returned. */
+static size_t parse_pchar(const char *uri_text, size_t 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 */
+ size_t j;
+ if (uri_text[i + 1] == 0 || uri_text[i + 2] == 0) {
+ return NOT_SET;
+ }
+ 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 NOT_SET;
+ }
+ }
+ return 2;
+ }
+ return 0;
+}
+
+/* *( pchar / "?" / "/" ) */
+static int parse_fragment_or_query(const char *uri_text, size_t *i) {
+ char c;
+ while ((c = uri_text[*i]) != 0) {
+ const size_t 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 1;
+ }
+ gpr_log(GPR_ERROR, "should never reach here");
+ abort();
+ default:
+ (*i) += advance;
+ break;
+ case NOT_SET: /* uri_text[i] introduces an invalid URI */
+ return 0;
+ }
+ }
+ /* *i is the first uri_text position past the \a query production, maybe \0 */
+ return 1;
+}
+
grpc_uri *grpc_uri_parse(const char *uri_text, int suppress_errors) {
grpc_uri *uri;
size_t scheme_begin = 0;
-#define NOT_SET (~(size_t)0)
size_t scheme_end = NOT_SET;
size_t authority_begin = NOT_SET;
size_t authority_end = NOT_SET;
size_t path_begin = NOT_SET;
size_t path_end = NOT_SET;
+ size_t query_begin = NOT_SET;
+ size_t query_end = NOT_SET;
+ size_t fragment_begin = NOT_SET;
+ size_t fragment_end = NOT_SET;
size_t i;
for (i = scheme_begin; uri_text[i] != 0; i++) {
@@ -103,15 +171,9 @@ grpc_uri *grpc_uri_parse(const char *uri_text, int suppress_errors) {
authority_begin = scheme_end + 3;
for (i = authority_begin; uri_text[i] != 0 && authority_end == NOT_SET;
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 == NOT_SET && uri_text[i] == 0) {
authority_end = i;
@@ -126,20 +188,46 @@ 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 == NOT_SET && uri_text[i] == 0) {
+ path_end = i;
+ }
+ if (path_end == NOT_SET) {
+ return bad_uri(uri_text, i, "path", suppress_errors);
+ }
+
+ if (uri_text[i] == '?') {
+ query_begin = ++i;
+ if (!parse_fragment_or_query(uri_text, &i)) {
+ 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;
+ if (!parse_fragment_or_query(uri_text, &i)) {
+ 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;
}
@@ -149,5 +237,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 */
diff --git a/src/core/compression/algorithm.c b/src/core/compression/algorithm.c
index 6ed6dbe93f..76d42fde0f 100644
--- a/src/core/compression/algorithm.c
+++ b/src/core/compression/algorithm.c
@@ -33,7 +33,9 @@
#include <stdlib.h>
#include <string.h>
+
#include <grpc/compression.h>
+#include <grpc/support/useful.h>
int grpc_compression_algorithm_parse(const char *name, size_t name_length,
grpc_compression_algorithm *algorithm) {
@@ -102,3 +104,24 @@ grpc_compression_level grpc_compression_level_for_algorithm(
}
abort();
}
+
+void grpc_compression_options_init(grpc_compression_options *opts) {
+ opts->enabled_algorithms_bitset = (1u << GRPC_COMPRESS_ALGORITHMS_COUNT)-1;
+ opts->default_compression_algorithm = GRPC_COMPRESS_NONE;
+}
+
+void grpc_compression_options_enable_algorithm(
+ grpc_compression_options *opts, grpc_compression_algorithm algorithm) {
+ GPR_BITSET(&opts->enabled_algorithms_bitset, algorithm);
+}
+
+void grpc_compression_options_disable_algorithm(
+ grpc_compression_options *opts, grpc_compression_algorithm algorithm) {
+ GPR_BITCLEAR(&opts->enabled_algorithms_bitset, algorithm);
+}
+
+int grpc_compression_options_is_algorithm_enabled(
+ const grpc_compression_options *opts,
+ grpc_compression_algorithm algorithm) {
+ return GPR_BITGET(opts->enabled_algorithms_bitset, algorithm);
+}
diff --git a/src/core/surface/call.c b/src/core/surface/call.c
index 16a7d2ec35..4168c2ef0c 100644
--- a/src/core/surface/call.c
+++ b/src/core/surface/call.c
@@ -534,7 +534,7 @@ static void set_encodings_accepted_by_peer(
gpr_slice_buffer accept_encoding_parts;
gpr_slice_buffer_init(&accept_encoding_parts);
- gpr_slice_split(accept_encoding_slice, ", ", &accept_encoding_parts);
+ gpr_slice_split(accept_encoding_slice, ",", &accept_encoding_parts);
/* No need to zero call->encodings_accepted_by_peer: grpc_call_create already
* zeroes the whole grpc_call */