Built motion from commit 6a09e18b.|2.6.11
[motion2.git] / legacy-libs / grpc / deps / grpc / src / core / ext / transport / chttp2 / transport / bin_decoder.cc
diff --git a/legacy-libs/grpc/deps/grpc/src/core/ext/transport/chttp2/transport/bin_decoder.cc b/legacy-libs/grpc/deps/grpc/src/core/ext/transport/chttp2/transport/bin_decoder.cc
new file mode 100644 (file)
index 0000000..249035d
--- /dev/null
@@ -0,0 +1,250 @@
+/*
+ *
+ * Copyright 2016 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include "src/core/ext/transport/chttp2/transport/bin_decoder.h"
+#include "src/core/lib/gpr/string.h"
+#include "src/core/lib/slice/slice_internal.h"
+#include "src/core/lib/slice/slice_string_helpers.h"
+
+static uint8_t decode_table[] = {
+    0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+    0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+    0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+    0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 62,   0x40, 0x40, 0x40, 63,
+    52,   53,   54,   55,   56,   57,   58,   59,   60,   61,   0x40, 0x40,
+    0x40, 0x40, 0x40, 0x40, 0x40, 0,    1,    2,    3,    4,    5,    6,
+    7,    8,    9,    10,   11,   12,   13,   14,   15,   16,   17,   18,
+    19,   20,   21,   22,   23,   24,   25,   0x40, 0x40, 0x40, 0x40, 0x40,
+    0x40, 26,   27,   28,   29,   30,   31,   32,   33,   34,   35,   36,
+    37,   38,   39,   40,   41,   42,   43,   44,   45,   46,   47,   48,
+    49,   50,   51,   0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+    0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+    0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+    0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+    0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+    0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+    0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+    0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+    0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+    0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+    0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+    0x40, 0x40, 0x40, 0x40};
+
+static const uint8_t tail_xtra[4] = {0, 0, 1, 2};
+
+static bool input_is_valid(const uint8_t* input_ptr, size_t length) {
+  size_t i;
+
+  for (i = 0; i < length; ++i) {
+    if (GPR_UNLIKELY((decode_table[input_ptr[i]] & 0xC0) != 0)) {
+      gpr_log(GPR_ERROR,
+              "Base64 decoding failed, invalid character '%c' in base64 "
+              "input.\n",
+              static_cast<char>(*input_ptr));
+      return false;
+    }
+  }
+  return true;
+}
+
+#define COMPOSE_OUTPUT_BYTE_0(input_ptr)        \
+  (uint8_t)((decode_table[input_ptr[0]] << 2) | \
+            (decode_table[input_ptr[1]] >> 4))
+
+#define COMPOSE_OUTPUT_BYTE_1(input_ptr)        \
+  (uint8_t)((decode_table[input_ptr[1]] << 4) | \
+            (decode_table[input_ptr[2]] >> 2))
+
+#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 (GPR_UNLIKELY(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 (GPR_UNLIKELY(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;
+
+  if (ctx->input_cur > ctx->input_end || ctx->output_cur > ctx->output_end) {
+    return false;
+  }
+
+  // Process a block of 4 input characters and 3 output bytes
+  while (ctx->input_end >= ctx->input_cur + 4 &&
+         ctx->output_end >= ctx->output_cur + 3) {
+    if (!input_is_valid(ctx->input_cur, 4)) return false;
+    ctx->output_cur[0] = COMPOSE_OUTPUT_BYTE_0(ctx->input_cur);
+    ctx->output_cur[1] = COMPOSE_OUTPUT_BYTE_1(ctx->input_cur);
+    ctx->output_cur[2] = COMPOSE_OUTPUT_BYTE_2(ctx->input_cur);
+    ctx->output_cur += 3;
+    ctx->input_cur += 4;
+  }
+
+  // Process the tail of input data
+  input_tail = static_cast<size_t>(ctx->input_end - ctx->input_cur);
+  if (input_tail == 4) {
+    // Process the input data with pad chars
+    if (ctx->input_cur[3] == '=') {
+      if (ctx->input_cur[2] == '=' && ctx->output_end >= ctx->output_cur + 1) {
+        if (!input_is_valid(ctx->input_cur, 2)) return false;
+        *(ctx->output_cur++) = COMPOSE_OUTPUT_BYTE_0(ctx->input_cur);
+        ctx->input_cur += 4;
+      } else if (ctx->output_end >= ctx->output_cur + 2) {
+        if (!input_is_valid(ctx->input_cur, 3)) return false;
+        *(ctx->output_cur++) = COMPOSE_OUTPUT_BYTE_0(ctx->input_cur);
+        *(ctx->output_cur++) = COMPOSE_OUTPUT_BYTE_1(ctx->input_cur);
+        ;
+        ctx->input_cur += 4;
+      }
+    }
+
+  } else if (ctx->contains_tail && input_tail > 1) {
+    // Process the input data without pad chars, but constains_tail is set
+    if (ctx->output_end >= ctx->output_cur + tail_xtra[input_tail]) {
+      if (!input_is_valid(ctx->input_cur, input_tail)) return false;
+      switch (input_tail) {
+        case 3:
+          ctx->output_cur[1] = COMPOSE_OUTPUT_BYTE_1(ctx->input_cur);
+        /* fallthrough */
+        case 2:
+          ctx->output_cur[0] = COMPOSE_OUTPUT_BYTE_0(ctx->input_cur);
+      }
+      ctx->output_cur += tail_xtra[input_tail];
+      ctx->input_cur += input_tail;
+    }
+  }
+
+  return true;
+}
+
+grpc_slice grpc_chttp2_base64_decode(const grpc_slice& input) {
+  size_t input_length = GRPC_SLICE_LENGTH(input);
+  size_t output_length = input_length / 4 * 3;
+  struct grpc_base64_decode_context ctx;
+  grpc_slice output;
+
+  if (GPR_UNLIKELY(input_length % 4 != 0)) {
+    gpr_log(GPR_ERROR,
+            "Base64 decoding failed, input of "
+            "grpc_chttp2_base64_decode has a length of %d, which is not a "
+            "multiple of 4.\n",
+            static_cast<int>(input_length));
+    return grpc_empty_slice();
+  }
+
+  if (input_length > 0) {
+    const uint8_t* input_end = GRPC_SLICE_END_PTR(input);
+    if (*(--input_end) == '=') {
+      output_length--;
+      if (*(--input_end) == '=') {
+        output_length--;
+      }
+    }
+  }
+  output = GRPC_SLICE_MALLOC(output_length);
+
+  ctx.input_cur = GRPC_SLICE_START_PTR(input);
+  ctx.input_end = GRPC_SLICE_END_PTR(input);
+  ctx.output_cur = GRPC_SLICE_START_PTR(output);
+  ctx.output_end = GRPC_SLICE_END_PTR(output);
+  ctx.contains_tail = false;
+
+  if (GPR_UNLIKELY(!grpc_base64_decode_partial(&ctx))) {
+    char* s = grpc_slice_to_c_string(input);
+    gpr_log(GPR_ERROR, "Base64 decoding failed, input string:\n%s\n", s);
+    gpr_free(s);
+    grpc_slice_unref_internal(output);
+    return grpc_empty_slice();
+  }
+  GPR_ASSERT(ctx.output_cur == GRPC_SLICE_END_PTR(output));
+  GPR_ASSERT(ctx.input_cur == GRPC_SLICE_END_PTR(input));
+  return output;
+}
+
+grpc_slice grpc_chttp2_base64_decode_with_length(const grpc_slice& input,
+                                                 size_t output_length) {
+  size_t input_length = GRPC_SLICE_LENGTH(input);
+  grpc_slice output = GRPC_SLICE_MALLOC(output_length);
+  struct grpc_base64_decode_context ctx;
+
+  // The length of a base64 string cannot be 4 * n + 1
+  if (GPR_UNLIKELY(input_length % 4 == 1)) {
+    gpr_log(GPR_ERROR,
+            "Base64 decoding failed, input of "
+            "grpc_chttp2_base64_decode_with_length has a length of %d, which "
+            "has a tail of 1 byte.\n",
+            static_cast<int>(input_length));
+    grpc_slice_unref_internal(output);
+    return grpc_empty_slice();
+  }
+
+  if (GPR_UNLIKELY(output_length >
+                   input_length / 4 * 3 + tail_xtra[input_length % 4])) {
+    gpr_log(
+        GPR_ERROR,
+        "Base64 decoding failed, output_length %d is longer "
+        "than the max possible output length %d.\n",
+        static_cast<int>(output_length),
+        static_cast<int>(input_length / 4 * 3 + tail_xtra[input_length % 4]));
+    grpc_slice_unref_internal(output);
+    return grpc_empty_slice();
+  }
+
+  ctx.input_cur = GRPC_SLICE_START_PTR(input);
+  ctx.input_end = GRPC_SLICE_END_PTR(input);
+  ctx.output_cur = GRPC_SLICE_START_PTR(output);
+  ctx.output_end = GRPC_SLICE_END_PTR(output);
+  ctx.contains_tail = true;
+
+  if (GPR_UNLIKELY(!grpc_base64_decode_partial(&ctx))) {
+    char* s = grpc_slice_to_c_string(input);
+    gpr_log(GPR_ERROR, "Base64 decoding failed, input string:\n%s\n", s);
+    gpr_free(s);
+    grpc_slice_unref_internal(output);
+    return grpc_empty_slice();
+  }
+  GPR_ASSERT(ctx.output_cur == GRPC_SLICE_END_PTR(output));
+  GPR_ASSERT(ctx.input_cur <= GRPC_SLICE_END_PTR(input));
+  return output;
+}