aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core
diff options
context:
space:
mode:
authorGravatar Mark D. Roth <roth@google.com>2016-09-08 07:16:34 -0700
committerGravatar Mark D. Roth <roth@google.com>2016-09-08 07:16:34 -0700
commitebfcd97940e6688a37c36cdeac87da3196ce1a9b (patch)
treefa284a70c6857e2cbb9aa127d109ba9f7e434798 /src/core
parent9717e5fe93a5b6d0042b43369655bb696a86bb9f (diff)
parent47b2961638328d29577361c3cb4dec5ab5bab537 (diff)
Merge remote-tracking branch 'upstream/master' into max_send_size_filter
Diffstat (limited to 'src/core')
-rw-r--r--src/core/ext/transport/chttp2/transport/chttp2_transport.c13
-rw-r--r--src/core/ext/transport/chttp2/transport/frame.h2
-rw-r--r--src/core/ext/transport/chttp2/transport/hpack_encoder.c10
-rw-r--r--src/core/ext/transport/chttp2/transport/hpack_encoder.h1
-rw-r--r--src/core/ext/transport/chttp2/transport/internal.h2
-rw-r--r--src/core/ext/transport/chttp2/transport/writing.c12
-rw-r--r--src/core/lib/channel/http_client_filter.c1
-rw-r--r--src/core/lib/support/percent_encoding.c180
-rw-r--r--src/core/lib/support/percent_encoding.h78
9 files changed, 290 insertions, 9 deletions
diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.c b/src/core/ext/transport/chttp2/transport/chttp2_transport.c
index 93d21c07d2..00b7fc4cc2 100644
--- a/src/core/ext/transport/chttp2/transport/chttp2_transport.c
+++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.c
@@ -399,6 +399,19 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
push_setting(exec_ctx, t, GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE,
(uint32_t)value);
}
+ } else if (0 == strcmp(channel_args->args[i].key,
+ GRPC_ARG_HTTP2_MAX_FRAME_SIZE)) {
+ if (channel_args->args[i].type != GRPC_ARG_INTEGER) {
+ gpr_log(GPR_ERROR, "%s: must be an integer",
+ GRPC_ARG_HTTP2_MAX_FRAME_SIZE);
+ } else if (channel_args->args[i].value.integer < 16384 ||
+ channel_args->args[i].value.integer > 16777215) {
+ gpr_log(GPR_ERROR, "%s: must be between 16384 and 16777215",
+ GRPC_ARG_HTTP2_MAX_FRAME_SIZE);
+ } else {
+ push_setting(exec_ctx, t, GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE,
+ (uint32_t)channel_args->args[i].value.integer);
+ }
}
}
}
diff --git a/src/core/ext/transport/chttp2/transport/frame.h b/src/core/ext/transport/chttp2/transport/frame.h
index 7776609367..507aae4100 100644
--- a/src/core/ext/transport/chttp2/transport/frame.h
+++ b/src/core/ext/transport/chttp2/transport/frame.h
@@ -52,8 +52,6 @@ typedef struct grpc_chttp2_transport_parsing grpc_chttp2_transport_parsing;
#define GRPC_CHTTP2_FRAME_GOAWAY 7
#define GRPC_CHTTP2_FRAME_WINDOW_UPDATE 8
-#define GRPC_CHTTP2_MAX_PAYLOAD_LENGTH ((1 << 14) - 1)
-
#define GRPC_CHTTP2_DATA_FLAG_END_STREAM 1
#define GRPC_CHTTP2_FLAG_ACK 1
#define GRPC_CHTTP2_DATA_FLAG_END_HEADERS 4
diff --git a/src/core/ext/transport/chttp2/transport/hpack_encoder.c b/src/core/ext/transport/chttp2/transport/hpack_encoder.c
index 2cb8205d94..581471ba02 100644
--- a/src/core/ext/transport/chttp2/transport/hpack_encoder.c
+++ b/src/core/ext/transport/chttp2/transport/hpack_encoder.c
@@ -78,6 +78,8 @@ typedef struct {
uint32_t stream_id;
gpr_slice_buffer *output;
grpc_transport_one_way_stats *stats;
+ /* maximum size of a frame */
+ size_t max_frame_size;
} framer_state;
/* fills p (which is expected to be 9 bytes long) with a data frame header */
@@ -123,7 +125,7 @@ static void begin_frame(framer_state *st) {
needed */
static void ensure_space(framer_state *st, size_t need_bytes) {
if (st->output->length - st->output_length_at_start_of_frame + need_bytes <=
- GRPC_CHTTP2_MAX_PAYLOAD_LENGTH) {
+ st->max_frame_size) {
return;
}
finish_frame(st, 0, 0);
@@ -149,8 +151,8 @@ static void add_header_data(framer_state *st, gpr_slice slice) {
size_t len = GPR_SLICE_LENGTH(slice);
size_t remaining;
if (len == 0) return;
- remaining = GRPC_CHTTP2_MAX_PAYLOAD_LENGTH +
- st->output_length_at_start_of_frame - st->output->length;
+ remaining = st->max_frame_size + st->output_length_at_start_of_frame -
+ st->output->length;
if (len <= remaining) {
st->stats->header_bytes += len;
gpr_slice_buffer_add(st->output, slice);
@@ -542,6 +544,7 @@ void grpc_chttp2_hpack_compressor_set_max_table_size(
void grpc_chttp2_encode_header(grpc_chttp2_hpack_compressor *c,
uint32_t stream_id,
grpc_metadata_batch *metadata, int is_eof,
+ size_t max_frame_size,
grpc_transport_one_way_stats *stats,
gpr_slice_buffer *outbuf) {
framer_state st;
@@ -555,6 +558,7 @@ void grpc_chttp2_encode_header(grpc_chttp2_hpack_compressor *c,
st.output = outbuf;
st.is_first_frame = 1;
st.stats = stats;
+ st.max_frame_size = max_frame_size;
/* Encode a metadata batch; store the returned values, representing
a metadata element that needs to be unreffed back into the metadata
diff --git a/src/core/ext/transport/chttp2/transport/hpack_encoder.h b/src/core/ext/transport/chttp2/transport/hpack_encoder.h
index 0f7b0b063a..4c3a931549 100644
--- a/src/core/ext/transport/chttp2/transport/hpack_encoder.h
+++ b/src/core/ext/transport/chttp2/transport/hpack_encoder.h
@@ -91,6 +91,7 @@ void grpc_chttp2_hpack_compressor_set_max_usable_size(
void grpc_chttp2_encode_header(grpc_chttp2_hpack_compressor *c, uint32_t id,
grpc_metadata_batch *metadata, int is_eof,
+ size_t max_frame_size,
grpc_transport_one_way_stats *stats,
gpr_slice_buffer *outbuf);
diff --git a/src/core/ext/transport/chttp2/transport/internal.h b/src/core/ext/transport/chttp2/transport/internal.h
index e1dcf5262a..d67c014e54 100644
--- a/src/core/ext/transport/chttp2/transport/internal.h
+++ b/src/core/ext/transport/chttp2/transport/internal.h
@@ -223,6 +223,8 @@ typedef struct {
uint8_t is_client;
/** callback for when writing is done */
grpc_closure done_cb;
+ /** maximum frame size */
+ uint32_t max_frame_size;
} grpc_chttp2_transport_writing;
struct grpc_chttp2_transport_parsing {
diff --git a/src/core/ext/transport/chttp2/transport/writing.c b/src/core/ext/transport/chttp2/transport/writing.c
index 8f7a1f55c6..311b26e354 100644
--- a/src/core/ext/transport/chttp2/transport/writing.c
+++ b/src/core/ext/transport/chttp2/transport/writing.c
@@ -51,6 +51,10 @@ int grpc_chttp2_unlocking_check_writes(
GPR_TIMER_BEGIN("grpc_chttp2_unlocking_check_writes", 0);
+ transport_writing->max_frame_size =
+ transport_global->settings[GRPC_ACKED_SETTINGS]
+ [GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE];
+
/* simple writes are queued to qbuf, and flushed here */
gpr_slice_buffer_swap(&transport_global->qbuf, &transport_writing->outbuf);
GPR_ASSERT(transport_global->qbuf.count == 0);
@@ -206,14 +210,15 @@ static void finalize_outbuf(grpc_exec_ctx *exec_ctx,
while (
grpc_chttp2_list_pop_writing_stream(transport_writing, &stream_writing)) {
uint32_t max_outgoing =
- (uint32_t)GPR_MIN(GRPC_CHTTP2_MAX_PAYLOAD_LENGTH,
+ (uint32_t)GPR_MIN(transport_writing->max_frame_size,
GPR_MIN(stream_writing->outgoing_window,
transport_writing->outgoing_window));
/* send initial metadata if it's available */
if (stream_writing->send_initial_metadata != NULL) {
grpc_chttp2_encode_header(
&transport_writing->hpack_compressor, stream_writing->id,
- stream_writing->send_initial_metadata, 0, &stream_writing->stats,
+ stream_writing->send_initial_metadata, 0,
+ transport_writing->max_frame_size, &stream_writing->stats,
&transport_writing->outbuf);
stream_writing->send_initial_metadata = NULL;
stream_writing->sent_initial_metadata = 1;
@@ -303,7 +308,8 @@ static void finalize_outbuf(grpc_exec_ctx *exec_ctx,
} else {
grpc_chttp2_encode_header(
&transport_writing->hpack_compressor, stream_writing->id,
- stream_writing->send_trailing_metadata, 1, &stream_writing->stats,
+ stream_writing->send_trailing_metadata, 1,
+ transport_writing->max_frame_size, &stream_writing->stats,
&transport_writing->outbuf);
}
if (!transport_writing->is_client && !stream_writing->read_closed) {
diff --git a/src/core/lib/channel/http_client_filter.c b/src/core/lib/channel/http_client_filter.c
index ef68cc86ea..edcc741ff6 100644
--- a/src/core/lib/channel/http_client_filter.c
+++ b/src/core/lib/channel/http_client_filter.c
@@ -233,7 +233,6 @@ static void hc_mutate_op(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
if (method == GRPC_MDELEM_METHOD_GET) {
/* allocate memory to hold the entire payload */
calld->payload_bytes = gpr_malloc(op->send_message->length);
- GPR_ASSERT(calld->payload_bytes);
/* read slices of send_message and copy into payload_bytes */
calld->send_op = *op;
diff --git a/src/core/lib/support/percent_encoding.c b/src/core/lib/support/percent_encoding.c
new file mode 100644
index 0000000000..3c19f264f9
--- /dev/null
+++ b/src/core/lib/support/percent_encoding.c
@@ -0,0 +1,180 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/support/percent_encoding.h"
+
+#include <grpc/support/log.h>
+
+const uint8_t gpr_url_percent_encoding_unreserved_bytes[256 / 8] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0xff, 0x03, 0xfe, 0xff, 0xff,
+ 0x87, 0xfe, 0xff, 0xff, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+const uint8_t gpr_compatible_percent_encoding_unreserved_bytes[256 / 8] = {
+ 0x00, 0x00, 0x00, 0x00, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+static bool is_unreserved_character(uint8_t c,
+ const uint8_t *unreserved_bytes) {
+ return ((unreserved_bytes[c / 8] >> (c % 8)) & 1) != 0;
+}
+
+gpr_slice gpr_percent_encode_slice(gpr_slice slice,
+ const uint8_t *unreserved_bytes) {
+ static const uint8_t hex[] = "0123456789ABCDEF";
+
+ // first pass: count the number of bytes needed to output this string
+ size_t output_length = 0;
+ const uint8_t *slice_start = GPR_SLICE_START_PTR(slice);
+ const uint8_t *slice_end = GPR_SLICE_END_PTR(slice);
+ const uint8_t *p;
+ bool any_reserved_bytes = false;
+ for (p = slice_start; p < slice_end; p++) {
+ bool unres = is_unreserved_character(*p, unreserved_bytes);
+ output_length += unres ? 1 : 3;
+ any_reserved_bytes |= !unres;
+ }
+ // no unreserved bytes: return the string unmodified
+ if (!any_reserved_bytes) {
+ return gpr_slice_ref(slice);
+ }
+ // second pass: actually encode
+ gpr_slice out = gpr_slice_malloc(output_length);
+ uint8_t *q = GPR_SLICE_START_PTR(out);
+ for (p = slice_start; p < slice_end; p++) {
+ if (is_unreserved_character(*p, unreserved_bytes)) {
+ *q++ = *p;
+ } else {
+ *q++ = '%';
+ *q++ = hex[*p >> 4];
+ *q++ = hex[*p & 15];
+ }
+ }
+ GPR_ASSERT(q == GPR_SLICE_END_PTR(out));
+ return out;
+}
+
+static bool valid_hex(const uint8_t *p, const uint8_t *end) {
+ if (p >= end) return false;
+ return (*p >= '0' && *p <= '9') || (*p >= 'a' && *p <= 'f') ||
+ (*p >= 'A' && *p <= 'F');
+}
+
+static uint8_t dehex(uint8_t c) {
+ if (c >= '0' && c <= '9') return (uint8_t)(c - '0');
+ if (c >= 'A' && c <= 'F') return (uint8_t)(c - 'A' + 10);
+ if (c >= 'a' && c <= 'f') return (uint8_t)(c - 'a' + 10);
+ GPR_UNREACHABLE_CODE(return 255);
+}
+
+bool gpr_strict_percent_decode_slice(gpr_slice slice_in,
+ const uint8_t *unreserved_bytes,
+ gpr_slice *slice_out) {
+ const uint8_t *p = GPR_SLICE_START_PTR(slice_in);
+ const uint8_t *in_end = GPR_SLICE_END_PTR(slice_in);
+ size_t out_length = 0;
+ bool any_percent_encoded_stuff = false;
+ while (p != in_end) {
+ if (*p == '%') {
+ if (!valid_hex(++p, in_end)) return false;
+ if (!valid_hex(++p, in_end)) return false;
+ p++;
+ out_length++;
+ any_percent_encoded_stuff = true;
+ } else if (is_unreserved_character(*p, unreserved_bytes)) {
+ p++;
+ out_length++;
+ } else {
+ return false;
+ }
+ }
+ if (!any_percent_encoded_stuff) {
+ *slice_out = gpr_slice_ref(slice_in);
+ return true;
+ }
+ p = GPR_SLICE_START_PTR(slice_in);
+ *slice_out = gpr_slice_malloc(out_length);
+ uint8_t *q = GPR_SLICE_START_PTR(*slice_out);
+ while (p != in_end) {
+ if (*p == '%') {
+ *q++ = (uint8_t)(dehex(p[1]) << 4) | (dehex(p[2]));
+ p += 3;
+ } else {
+ *q++ = *p++;
+ }
+ }
+ GPR_ASSERT(q == GPR_SLICE_END_PTR(*slice_out));
+ return true;
+}
+
+gpr_slice gpr_permissive_percent_decode_slice(gpr_slice slice_in) {
+ const uint8_t *p = GPR_SLICE_START_PTR(slice_in);
+ const uint8_t *in_end = GPR_SLICE_END_PTR(slice_in);
+ size_t out_length = 0;
+ bool any_percent_encoded_stuff = false;
+ while (p != in_end) {
+ if (*p == '%') {
+ if (!valid_hex(p + 1, in_end) || !valid_hex(p + 2, in_end)) {
+ p++;
+ out_length++;
+ } else {
+ p += 3;
+ out_length++;
+ any_percent_encoded_stuff = true;
+ }
+ } else {
+ p++;
+ out_length++;
+ }
+ }
+ if (!any_percent_encoded_stuff) {
+ return gpr_slice_ref(slice_in);
+ }
+ p = GPR_SLICE_START_PTR(slice_in);
+ gpr_slice out = gpr_slice_malloc(out_length);
+ uint8_t *q = GPR_SLICE_START_PTR(out);
+ while (p != in_end) {
+ if (*p == '%') {
+ if (!valid_hex(p + 1, in_end) || !valid_hex(p + 2, in_end)) {
+ *q++ = *p++;
+ } else {
+ *q++ = (uint8_t)(dehex(p[1]) << 4) | (dehex(p[2]));
+ p += 3;
+ }
+ } else {
+ *q++ = *p++;
+ }
+ }
+ GPR_ASSERT(q == GPR_SLICE_END_PTR(out));
+ return out;
+}
diff --git a/src/core/lib/support/percent_encoding.h b/src/core/lib/support/percent_encoding.h
new file mode 100644
index 0000000000..000bf14ede
--- /dev/null
+++ b/src/core/lib/support/percent_encoding.h
@@ -0,0 +1,78 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_SUPPORT_PERCENT_ENCODING_H
+#define GRPC_CORE_LIB_SUPPORT_PERCENT_ENCODING_H
+
+/* Percent encoding and decoding of slices.
+ Transforms arbitrary strings into safe-for-transmission strings by using
+ variants of percent encoding (RFC 3986).
+ Two major variants are supplied: one that strictly matches URL encoding,
+ and another which applies percent encoding only to non-http2 header
+ bytes (the 'compatible' variant) */
+
+#include <stdbool.h>
+
+#include <grpc/support/slice.h>
+
+/* URL percent encoding spec bitfield (usabel as 'unreserved_bytes' in
+ gpr_percent_encode_slice, gpr_strict_percent_decode_slice).
+ Flags [A-Za-z0-9-_.~] as unreserved bytes for the percent encoding routines
+ */
+extern const uint8_t gpr_url_percent_encoding_unreserved_bytes[256 / 8];
+/* URL percent encoding spec bitfield (usabel as 'unreserved_bytes' in
+ gpr_percent_encode_slice, gpr_strict_percent_decode_slice).
+ Flags ascii7 non-control characters excluding '%' as unreserved bytes for the
+ percent encoding routines */
+extern const uint8_t gpr_compatible_percent_encoding_unreserved_bytes[256 / 8];
+
+/* Percent-encode a slice, returning the new slice (this cannot fail):
+ unreserved_bytes is a bitfield indicating which bytes are considered
+ unreserved and thus do not need percent encoding */
+gpr_slice gpr_percent_encode_slice(gpr_slice slice,
+ const uint8_t *unreserved_bytes);
+/* Percent-decode a slice, strictly.
+ If the input is legal (contains no unreserved bytes, and legal % encodings),
+ returns true and sets *slice_out to the decoded slice.
+ If the input is not legal, returns false and leaves *slice_out untouched.
+ unreserved_bytes is a bitfield indicating which bytes are considered
+ unreserved and thus do not need percent encoding */
+bool gpr_strict_percent_decode_slice(gpr_slice slice_in,
+ const uint8_t *unreserved_bytes,
+ gpr_slice *slice_out);
+/* Percent-decode a slice, permissively.
+ If a % triplet can not be decoded, pass it through verbatim.
+ This cannot fail. */
+gpr_slice gpr_permissive_percent_decode_slice(gpr_slice slice_in);
+
+#endif /* GRPC_CORE_LIB_SUPPORT_PERCENT_ENCODING_H */