aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/ext/transport
diff options
context:
space:
mode:
authorGravatar Muxi Yan <muxi@users.noreply.github.com>2018-02-21 23:35:38 -0800
committerGravatar GitHub <noreply@github.com>2018-02-21 23:35:38 -0800
commit0aa0324058e22723d227bd28876aae7fdb2ffd27 (patch)
treee46006820f106432e0cdc78fc440887fd2b558d3 /src/core/ext/transport
parenta6ed5165a2140260b7c4edcbdc210b0ae0c12ed3 (diff)
parent48396479c04d3ba40ad46be768bdf79840a65cbc (diff)
Merge pull request #14433 from muxi/add-cronet-bin-base64
Add binary metadata support for cronet transport
Diffstat (limited to 'src/core/ext/transport')
-rw-r--r--src/core/ext/transport/chttp2/transport/bin_decoder.cc26
-rw-r--r--src/core/ext/transport/chttp2/transport/bin_decoder.h3
-rw-r--r--src/core/ext/transport/cronet/transport/cronet_transport.cc60
3 files changed, 67 insertions, 22 deletions
diff --git a/src/core/ext/transport/chttp2/transport/bin_decoder.cc b/src/core/ext/transport/chttp2/transport/bin_decoder.cc
index 91980e6974..831a36961e 100644
--- a/src/core/ext/transport/chttp2/transport/bin_decoder.cc
+++ b/src/core/ext/transport/chttp2/transport/bin_decoder.cc
@@ -75,6 +75,32 @@ static bool input_is_valid(uint8_t* input_ptr, size_t length) {
#define COMPOSE_OUTPUT_BYTE_2(input_ptr) \
(uint8_t)((decode_table[input_ptr[2]] << 6) | decode_table[input_ptr[3]])
+// By RFC 4648, if the length of the encoded string without padding is 4n+r,
+// the length of decoded string is: 1) 3n if r = 0, 2) 3n + 1 if r = 2, 3, or
+// 3) invalid if r = 1.
+size_t grpc_chttp2_base64_infer_length_after_decode(const grpc_slice& slice) {
+ size_t len = GRPC_SLICE_LENGTH(slice);
+ const uint8_t* bytes = GRPC_SLICE_START_PTR(slice);
+ while (len > 0 && bytes[len - 1] == '=') {
+ len--;
+ }
+ if (GRPC_SLICE_LENGTH(slice) - len > 2) {
+ gpr_log(GPR_ERROR,
+ "Base64 decoding failed. Input has more than 2 paddings.");
+ return 0;
+ }
+ size_t tuples = len / 4;
+ size_t tail_case = len % 4;
+ if (tail_case == 1) {
+ gpr_log(GPR_ERROR,
+ "Base64 decoding failed. Input has a length of %zu (without"
+ " padding), which is invalid.\n",
+ len);
+ return 0;
+ }
+ return tuples * 3 + tail_xtra[tail_case];
+}
+
bool grpc_base64_decode_partial(struct grpc_base64_decode_context* ctx) {
size_t input_tail;
diff --git a/src/core/ext/transport/chttp2/transport/bin_decoder.h b/src/core/ext/transport/chttp2/transport/bin_decoder.h
index 9cb75ccd81..a0d74fb20d 100644
--- a/src/core/ext/transport/chttp2/transport/bin_decoder.h
+++ b/src/core/ext/transport/chttp2/transport/bin_decoder.h
@@ -48,4 +48,7 @@ grpc_slice grpc_chttp2_base64_decode(grpc_slice input);
grpc_slice grpc_chttp2_base64_decode_with_length(grpc_slice input,
size_t output_length);
+/* Infer the length of decoded data from encoded data. */
+size_t grpc_chttp2_base64_infer_length_after_decode(const grpc_slice& slice);
+
#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_BIN_DECODER_H */
diff --git a/src/core/ext/transport/cronet/transport/cronet_transport.cc b/src/core/ext/transport/cronet/transport/cronet_transport.cc
index 8904c122a7..c367f9c465 100644
--- a/src/core/ext/transport/cronet/transport/cronet_transport.cc
+++ b/src/core/ext/transport/cronet/transport/cronet_transport.cc
@@ -24,6 +24,8 @@
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
+#include "src/core/ext/transport/chttp2/transport/bin_decoder.h"
+#include "src/core/ext/transport/chttp2/transport/bin_encoder.h"
#include "src/core/ext/transport/chttp2/transport/incoming_metadata.h"
#include "src/core/ext/transport/cronet/transport/cronet_transport.h"
#include "src/core/lib/gpr/host_port.h"
@@ -393,6 +395,29 @@ static void execute_from_storage(stream_obj* s) {
gpr_mu_unlock(&s->mu);
}
+static void convert_cronet_array_to_metadata(
+ const bidirectional_stream_header_array* header_array,
+ grpc_chttp2_incoming_metadata_buffer* mds) {
+ for (size_t i = 0; i < header_array->count; i++) {
+ CRONET_LOG(GPR_DEBUG, "header key=%s, value=%s",
+ header_array->headers[i].key, header_array->headers[i].value);
+ grpc_slice key = grpc_slice_intern(
+ grpc_slice_from_static_string(header_array->headers[i].key));
+ grpc_slice value;
+ if (grpc_is_binary_header(key)) {
+ value = grpc_slice_from_static_string(header_array->headers[i].value);
+ value = grpc_slice_intern(grpc_chttp2_base64_decode_with_length(
+ value, grpc_chttp2_base64_infer_length_after_decode(value)));
+ } else {
+ value = grpc_slice_intern(
+ grpc_slice_from_static_string(header_array->headers[i].value));
+ }
+ GRPC_LOG_IF_ERROR("convert_cronet_array_to_metadata",
+ grpc_chttp2_incoming_metadata_buffer_add(
+ mds, grpc_mdelem_from_slices(key, value)));
+ }
+}
+
/*
Cronet callback
*/
@@ -517,16 +542,7 @@ static void on_response_headers_received(
sizeof(s->state.rs.initial_metadata));
grpc_chttp2_incoming_metadata_buffer_init(&s->state.rs.initial_metadata,
s->arena);
- for (size_t i = 0; i < headers->count; i++) {
- GRPC_LOG_IF_ERROR("on_response_headers_received",
- grpc_chttp2_incoming_metadata_buffer_add(
- &s->state.rs.initial_metadata,
- grpc_mdelem_from_slices(
- grpc_slice_intern(grpc_slice_from_static_string(
- headers->headers[i].key)),
- grpc_slice_intern(grpc_slice_from_static_string(
- headers->headers[i].value)))));
- }
+ convert_cronet_array_to_metadata(headers, &s->state.rs.initial_metadata);
s->state.state_callback_received[OP_RECV_INITIAL_METADATA] = true;
if (!(s->state.state_op_done[OP_CANCEL_ERROR] ||
s->state.state_callback_received[OP_FAILED])) {
@@ -621,18 +637,11 @@ static void on_response_trailers_received(
s->state.rs.trailing_metadata_valid = false;
grpc_chttp2_incoming_metadata_buffer_init(&s->state.rs.trailing_metadata,
s->arena);
- for (size_t i = 0; i < trailers->count; i++) {
- CRONET_LOG(GPR_DEBUG, "trailer key=%s, value=%s", trailers->headers[i].key,
- trailers->headers[i].value);
- GRPC_LOG_IF_ERROR("on_response_trailers_received",
- grpc_chttp2_incoming_metadata_buffer_add(
- &s->state.rs.trailing_metadata,
- grpc_mdelem_from_slices(
- grpc_slice_intern(grpc_slice_from_static_string(
- trailers->headers[i].key)),
- grpc_slice_intern(grpc_slice_from_static_string(
- trailers->headers[i].value)))));
+ convert_cronet_array_to_metadata(trailers, &s->state.rs.trailing_metadata);
+ if (trailers->count > 0) {
s->state.rs.trailing_metadata_valid = true;
+ }
+ for (size_t i = 0; i < trailers->count; i++) {
if (0 == strcmp(trailers->headers[i].key, "grpc-status") &&
0 != strcmp(trailers->headers[i].value, "0")) {
s->state.fail_state = true;
@@ -721,7 +730,14 @@ static void convert_metadata_to_cronet_headers(
grpc_mdelem mdelem = curr->md;
curr = curr->next;
char* key = grpc_slice_to_c_string(GRPC_MDKEY(mdelem));
- char* value = grpc_slice_to_c_string(GRPC_MDVALUE(mdelem));
+ char* value;
+ if (grpc_is_binary_header(GRPC_MDKEY(mdelem))) {
+ grpc_slice wire_value = grpc_chttp2_base64_encode(GRPC_MDVALUE(mdelem));
+ value = grpc_slice_to_c_string(wire_value);
+ grpc_slice_unref(wire_value);
+ } else {
+ value = grpc_slice_to_c_string(GRPC_MDVALUE(mdelem));
+ }
if (grpc_slice_eq(GRPC_MDKEY(mdelem), GRPC_MDSTR_SCHEME) ||
grpc_slice_eq(GRPC_MDKEY(mdelem), GRPC_MDSTR_AUTHORITY)) {
/* Cronet populates these fields on its own */