diff options
author | 2018-02-21 23:35:38 -0800 | |
---|---|---|
committer | 2018-02-21 23:35:38 -0800 | |
commit | 0aa0324058e22723d227bd28876aae7fdb2ffd27 (patch) | |
tree | e46006820f106432e0cdc78fc440887fd2b558d3 /src/core/ext/transport | |
parent | a6ed5165a2140260b7c4edcbdc210b0ae0c12ed3 (diff) | |
parent | 48396479c04d3ba40ad46be768bdf79840a65cbc (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')
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 */ |