bin_decoder.cc
Go to the documentation of this file.
1 /*
2  *
3  * Copyright 2016 gRPC authors.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */
18 
20 
22 
23 #include "absl/base/attributes.h"
24 
25 #include <grpc/support/alloc.h>
26 #include <grpc/support/log.h>
27 
29 
30 static uint8_t decode_table[] = {
31  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
32  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
33  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
34  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 62, 0x40, 0x40, 0x40, 63,
35  52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0x40, 0x40,
36  0x40, 0x40, 0x40, 0x40, 0x40, 0, 1, 2, 3, 4, 5, 6,
37  7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
38  19, 20, 21, 22, 23, 24, 25, 0x40, 0x40, 0x40, 0x40, 0x40,
39  0x40, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
40  37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
41  49, 50, 51, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
42  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
43  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
44  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
45  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
46  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
47  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
48  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
49  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
50  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
51  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
52  0x40, 0x40, 0x40, 0x40};
53 
54 static const uint8_t tail_xtra[4] = {0, 0, 1, 2};
55 
56 static bool input_is_valid(const uint8_t* input_ptr, size_t length) {
57  size_t i;
58 
59  for (i = 0; i < length; ++i) {
60  if (GPR_UNLIKELY((decode_table[input_ptr[i]] & 0xC0) != 0)) {
62  "Base64 decoding failed, invalid character '%c' in base64 "
63  "input.\n",
64  static_cast<char>(*input_ptr));
65  return false;
66  }
67  }
68  return true;
69 }
70 
71 #define COMPOSE_OUTPUT_BYTE_0(input_ptr) \
72  (uint8_t)((decode_table[(input_ptr)[0]] << 2) | \
73  (decode_table[(input_ptr)[1]] >> 4))
74 
75 #define COMPOSE_OUTPUT_BYTE_1(input_ptr) \
76  (uint8_t)((decode_table[(input_ptr)[1]] << 4) | \
77  (decode_table[(input_ptr)[2]] >> 2))
78 
79 #define COMPOSE_OUTPUT_BYTE_2(input_ptr) \
80  (uint8_t)((decode_table[(input_ptr)[2]] << 6) | decode_table[(input_ptr)[3]])
81 
82 // By RFC 4648, if the length of the encoded string without padding is 4n+r,
83 // the length of decoded string is: 1) 3n if r = 0, 2) 3n + 1 if r = 2, 3, or
84 // 3) invalid if r = 1.
86  size_t len = GRPC_SLICE_LENGTH(slice);
88  while (len > 0 && bytes[len - 1] == '=') {
89  len--;
90  }
93  "Base64 decoding failed. Input has more than 2 paddings.");
94  return 0;
95  }
96  size_t tuples = len / 4;
97  size_t tail_case = len % 4;
98  if (GPR_UNLIKELY(tail_case == 1)) {
100  "Base64 decoding failed. Input has a length of %zu (without"
101  " padding), which is invalid.\n",
102  len);
103  return 0;
104  }
105  return tuples * 3 + tail_xtra[tail_case];
106 }
107 
109  size_t input_tail;
110 
111  if (ctx->input_cur > ctx->input_end || ctx->output_cur > ctx->output_end) {
112  return false;
113  }
114 
115  // Process a block of 4 input characters and 3 output bytes
116  while (ctx->input_end >= ctx->input_cur + 4 &&
117  ctx->output_end >= ctx->output_cur + 3) {
118  if (!input_is_valid(ctx->input_cur, 4)) return false;
119  ctx->output_cur[0] = COMPOSE_OUTPUT_BYTE_0(ctx->input_cur);
120  ctx->output_cur[1] = COMPOSE_OUTPUT_BYTE_1(ctx->input_cur);
121  ctx->output_cur[2] = COMPOSE_OUTPUT_BYTE_2(ctx->input_cur);
122  ctx->output_cur += 3;
123  ctx->input_cur += 4;
124  }
125 
126  // Process the tail of input data
127  input_tail = static_cast<size_t>(ctx->input_end - ctx->input_cur);
128  if (input_tail == 4) {
129  // Process the input data with pad chars
130  if (ctx->input_cur[3] == '=') {
131  if (ctx->input_cur[2] == '=' && ctx->output_end >= ctx->output_cur + 1) {
132  if (!input_is_valid(ctx->input_cur, 2)) return false;
133  *(ctx->output_cur++) = COMPOSE_OUTPUT_BYTE_0(ctx->input_cur);
134  ctx->input_cur += 4;
135  } else if (ctx->output_end >= ctx->output_cur + 2) {
136  if (!input_is_valid(ctx->input_cur, 3)) return false;
137  *(ctx->output_cur++) = COMPOSE_OUTPUT_BYTE_0(ctx->input_cur);
138  *(ctx->output_cur++) = COMPOSE_OUTPUT_BYTE_1(ctx->input_cur);
139  ;
140  ctx->input_cur += 4;
141  }
142  }
143 
144  } else if (ctx->contains_tail && input_tail > 1) {
145  // Process the input data without pad chars, but constains_tail is set
146  if (ctx->output_end >= ctx->output_cur + tail_xtra[input_tail]) {
147  if (!input_is_valid(ctx->input_cur, input_tail)) return false;
148  switch (input_tail) {
149  case 3:
150  ctx->output_cur[1] = COMPOSE_OUTPUT_BYTE_1(ctx->input_cur);
152  case 2:
153  ctx->output_cur[0] = COMPOSE_OUTPUT_BYTE_0(ctx->input_cur);
154  }
155  ctx->output_cur += tail_xtra[input_tail];
156  ctx->input_cur += input_tail;
157  }
158  }
159 
160  return true;
161 }
162 
164  size_t input_length = GRPC_SLICE_LENGTH(input);
165  size_t output_length = input_length / 4 * 3;
168 
169  if (GPR_UNLIKELY(input_length % 4 != 0)) {
171  "Base64 decoding failed, input of "
172  "grpc_chttp2_base64_decode has a length of %d, which is not a "
173  "multiple of 4.\n",
174  static_cast<int>(input_length));
175  return grpc_empty_slice();
176  }
177 
178  if (input_length > 0) {
180  if (*(--input_end) == '=') {
181  output_length--;
182  if (*(--input_end) == '=') {
183  output_length--;
184  }
185  }
186  }
187  output = GRPC_SLICE_MALLOC(output_length);
188 
189  ctx.input_cur = GRPC_SLICE_START_PTR(input);
190  ctx.input_end = GRPC_SLICE_END_PTR(input);
191  ctx.output_cur = GRPC_SLICE_START_PTR(output);
192  ctx.output_end = GRPC_SLICE_END_PTR(output);
193  ctx.contains_tail = false;
194 
196  char* s = grpc_slice_to_c_string(input);
197  gpr_log(GPR_ERROR, "Base64 decoding failed, input string:\n%s\n", s);
198  gpr_free(s);
200  return grpc_empty_slice();
201  }
202  GPR_ASSERT(ctx.output_cur == GRPC_SLICE_END_PTR(output));
203  GPR_ASSERT(ctx.input_cur == GRPC_SLICE_END_PTR(input));
204  return output;
205 }
206 
208  size_t output_length) {
209  size_t input_length = GRPC_SLICE_LENGTH(input);
210  grpc_slice output = GRPC_SLICE_MALLOC(output_length);
212 
213  // The length of a base64 string cannot be 4 * n + 1
214  if (GPR_UNLIKELY(input_length % 4 == 1)) {
216  "Base64 decoding failed, input of "
217  "grpc_chttp2_base64_decode_with_length has a length of %d, which "
218  "has a tail of 1 byte.\n",
219  static_cast<int>(input_length));
221  return grpc_empty_slice();
222  }
223 
224  if (GPR_UNLIKELY(output_length >
225  input_length / 4 * 3 + tail_xtra[input_length % 4])) {
226  gpr_log(
227  GPR_ERROR,
228  "Base64 decoding failed, output_length %d is longer "
229  "than the max possible output length %d.\n",
230  static_cast<int>(output_length),
231  static_cast<int>(input_length / 4 * 3 + tail_xtra[input_length % 4]));
233  return grpc_empty_slice();
234  }
235 
236  ctx.input_cur = GRPC_SLICE_START_PTR(input);
237  ctx.input_end = GRPC_SLICE_END_PTR(input);
238  ctx.output_cur = GRPC_SLICE_START_PTR(output);
239  ctx.output_end = GRPC_SLICE_END_PTR(output);
240  ctx.contains_tail = true;
241 
243  char* s = grpc_slice_to_c_string(input);
244  gpr_log(GPR_ERROR, "Base64 decoding failed, input string:\n%s\n", s);
245  gpr_free(s);
247  return grpc_empty_slice();
248  }
249  GPR_ASSERT(ctx.output_cur == GRPC_SLICE_END_PTR(output));
250  GPR_ASSERT(ctx.input_cur <= GRPC_SLICE_END_PTR(input));
251  return output;
252 }
grpc_chttp2_base64_infer_length_after_decode
size_t grpc_chttp2_base64_infer_length_after_decode(const grpc_slice &slice)
Definition: bin_decoder.cc:85
log.h
grpc_base64_decode_context::input_end
const uint8_t * input_end
Definition: bin_decoder.h:32
ctx
Definition: benchmark-async.c:30
gpr_free
GPRAPI void gpr_free(void *ptr)
Definition: alloc.cc:51
GRPC_SLICE_MALLOC
#define GRPC_SLICE_MALLOC(len)
Definition: include/grpc/slice.h:70
uint8_t
unsigned char uint8_t
Definition: stdint-msvc2008.h:78
COMPOSE_OUTPUT_BYTE_2
#define COMPOSE_OUTPUT_BYTE_2(input_ptr)
Definition: bin_decoder.cc:79
GPR_ASSERT
#define GPR_ASSERT(x)
Definition: include/grpc/impl/codegen/log.h:94
gmock_output_test.output
output
Definition: bloaty/third_party/googletest/googlemock/test/gmock_output_test.py:175
slice
grpc_slice slice
Definition: src/core/lib/surface/server.cc:467
gpr_log
GPRAPI void gpr_log(const char *file, int line, gpr_log_severity severity, const char *format,...) GPR_PRINT_FORMAT_CHECK(4
GPR_UNLIKELY
#define GPR_UNLIKELY(x)
Definition: impl/codegen/port_platform.h:770
GRPC_SLICE_START_PTR
#define GRPC_SLICE_START_PTR(slice)
Definition: include/grpc/impl/codegen/slice.h:101
grpc_empty_slice
GPRAPI grpc_slice grpc_empty_slice(void)
Definition: slice/slice.cc:42
grpc_slice
Definition: include/grpc/impl/codegen/slice.h:65
grpc_chttp2_base64_decode
grpc_slice grpc_chttp2_base64_decode(const grpc_slice &input)
Definition: bin_decoder.cc:163
input_is_valid
static bool input_is_valid(const uint8_t *input_ptr, size_t length)
Definition: bin_decoder.cc:56
GPR_ERROR
#define GPR_ERROR
Definition: include/grpc/impl/codegen/log.h:57
GRPC_SLICE_END_PTR
#define GRPC_SLICE_END_PTR(slice)
Definition: include/grpc/impl/codegen/slice.h:110
GRPC_SLICE_LENGTH
#define GRPC_SLICE_LENGTH(slice)
Definition: include/grpc/impl/codegen/slice.h:104
grpc_slice_to_c_string
GPRAPI char * grpc_slice_to_c_string(grpc_slice s)
Definition: slice/slice.cc:35
COMPOSE_OUTPUT_BYTE_1
#define COMPOSE_OUTPUT_BYTE_1(input_ptr)
Definition: bin_decoder.cc:75
decode_table
static uint8_t decode_table[]
Definition: bin_decoder.cc:30
bytes
uint8 bytes[10]
Definition: bloaty/third_party/protobuf/src/google/protobuf/io/coded_stream_unittest.cc:153
alloc.h
grpc_chttp2_base64_decode_with_length
grpc_slice grpc_chttp2_base64_decode_with_length(const grpc_slice &input, size_t output_length)
Definition: bin_decoder.cc:207
grpc_base64_decode_partial
bool grpc_base64_decode_partial(struct grpc_base64_decode_context *ctx)
Definition: bin_decoder.cc:108
slice_refcount.h
input
std::string input
Definition: bloaty/third_party/protobuf/src/google/protobuf/io/tokenizer_unittest.cc:197
COMPOSE_OUTPUT_BYTE_0
#define COMPOSE_OUTPUT_BYTE_0(input_ptr)
Definition: bin_decoder.cc:71
tail_xtra
static const uint8_t tail_xtra[4]
Definition: bin_decoder.cc:54
len
int len
Definition: abseil-cpp/absl/base/internal/low_level_alloc_test.cc:46
length
std::size_t length
Definition: abseil-cpp/absl/time/internal/test_util.cc:57
ABSL_FALLTHROUGH_INTENDED
#define ABSL_FALLTHROUGH_INTENDED
Definition: abseil-cpp/absl/base/attributes.h:641
bin_decoder.h
grpc_base64_decode_context
Definition: bin_decoder.h:29
i
uint64_t i
Definition: abseil-cpp/absl/container/btree_benchmark.cc:230
grpc_slice_unref_internal
void grpc_slice_unref_internal(const grpc_slice &slice)
Definition: slice_refcount.h:39
port_platform.h


grpc
Author(s):
autogenerated on Thu Mar 13 2025 02:58:37