1 /*
2 *
3 * Copyright 2015 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
19 #include <grpc/support/port_platform.h>
20
21 #include <stdlib.h>
22 #include <string.h>
23
24 #include <grpc/compression.h>
25
26 #include "src/core/lib/compression/algorithm_metadata.h"
27 #include "src/core/lib/compression/compression_internal.h"
28 #include "src/core/lib/gpr/useful.h"
29 #include "src/core/lib/surface/api_trace.h"
30 #include "src/core/lib/transport/static_metadata.h"
31
32 /* Interfaces related to MD */
33
34 grpc_message_compression_algorithm
grpc_message_compression_algorithm_from_slice(grpc_slice str)35 grpc_message_compression_algorithm_from_slice(grpc_slice str) {
36 if (grpc_slice_eq(str, GRPC_MDSTR_IDENTITY))
37 return GRPC_MESSAGE_COMPRESS_NONE;
38 if (grpc_slice_eq(str, GRPC_MDSTR_DEFLATE))
39 return GRPC_MESSAGE_COMPRESS_DEFLATE;
40 if (grpc_slice_eq(str, GRPC_MDSTR_GZIP)) return GRPC_MESSAGE_COMPRESS_GZIP;
41 return GRPC_MESSAGE_COMPRESS_ALGORITHMS_COUNT;
42 }
43
grpc_stream_compression_algorithm_from_slice(grpc_slice str)44 grpc_stream_compression_algorithm grpc_stream_compression_algorithm_from_slice(
45 grpc_slice str) {
46 if (grpc_slice_eq(str, GRPC_MDSTR_IDENTITY)) return GRPC_STREAM_COMPRESS_NONE;
47 if (grpc_slice_eq(str, GRPC_MDSTR_GZIP)) return GRPC_STREAM_COMPRESS_GZIP;
48 return GRPC_STREAM_COMPRESS_ALGORITHMS_COUNT;
49 }
50
grpc_message_compression_encoding_mdelem(grpc_message_compression_algorithm algorithm)51 grpc_mdelem grpc_message_compression_encoding_mdelem(
52 grpc_message_compression_algorithm algorithm) {
53 switch (algorithm) {
54 case GRPC_MESSAGE_COMPRESS_NONE:
55 return GRPC_MDELEM_GRPC_ENCODING_IDENTITY;
56 case GRPC_MESSAGE_COMPRESS_DEFLATE:
57 return GRPC_MDELEM_GRPC_ENCODING_DEFLATE;
58 case GRPC_MESSAGE_COMPRESS_GZIP:
59 return GRPC_MDELEM_GRPC_ENCODING_GZIP;
60 default:
61 break;
62 }
63 return GRPC_MDNULL;
64 }
65
grpc_stream_compression_encoding_mdelem(grpc_stream_compression_algorithm algorithm)66 grpc_mdelem grpc_stream_compression_encoding_mdelem(
67 grpc_stream_compression_algorithm algorithm) {
68 switch (algorithm) {
69 case GRPC_STREAM_COMPRESS_NONE:
70 return GRPC_MDELEM_CONTENT_ENCODING_IDENTITY;
71 case GRPC_STREAM_COMPRESS_GZIP:
72 return GRPC_MDELEM_CONTENT_ENCODING_GZIP;
73 default:
74 break;
75 }
76 return GRPC_MDNULL;
77 }
78
79 /* Interfaces performing transformation between compression algorithms and
80 * levels. */
81 grpc_message_compression_algorithm
grpc_compression_algorithm_to_message_compression_algorithm(grpc_compression_algorithm algo)82 grpc_compression_algorithm_to_message_compression_algorithm(
83 grpc_compression_algorithm algo) {
84 switch (algo) {
85 case GRPC_COMPRESS_DEFLATE:
86 return GRPC_MESSAGE_COMPRESS_DEFLATE;
87 case GRPC_COMPRESS_GZIP:
88 return GRPC_MESSAGE_COMPRESS_GZIP;
89 default:
90 return GRPC_MESSAGE_COMPRESS_NONE;
91 }
92 }
93
94 grpc_stream_compression_algorithm
grpc_compression_algorithm_to_stream_compression_algorithm(grpc_compression_algorithm algo)95 grpc_compression_algorithm_to_stream_compression_algorithm(
96 grpc_compression_algorithm algo) {
97 switch (algo) {
98 case GRPC_COMPRESS_STREAM_GZIP:
99 return GRPC_STREAM_COMPRESS_GZIP;
100 default:
101 return GRPC_STREAM_COMPRESS_NONE;
102 }
103 }
104
grpc_compression_bitset_to_message_bitset(uint32_t bitset)105 uint32_t grpc_compression_bitset_to_message_bitset(uint32_t bitset) {
106 return bitset & ((1u << GRPC_MESSAGE_COMPRESS_ALGORITHMS_COUNT) - 1);
107 }
108
grpc_compression_bitset_to_stream_bitset(uint32_t bitset)109 uint32_t grpc_compression_bitset_to_stream_bitset(uint32_t bitset) {
110 uint32_t identity = (bitset & 1u);
111 uint32_t other_bits =
112 (bitset >> (GRPC_MESSAGE_COMPRESS_ALGORITHMS_COUNT - 1)) &
113 ((1u << GRPC_STREAM_COMPRESS_ALGORITHMS_COUNT) - 2);
114 return identity | other_bits;
115 }
116
grpc_compression_bitset_from_message_stream_compression_bitset(uint32_t message_bitset,uint32_t stream_bitset)117 uint32_t grpc_compression_bitset_from_message_stream_compression_bitset(
118 uint32_t message_bitset, uint32_t stream_bitset) {
119 uint32_t offset_stream_bitset =
120 (stream_bitset & 1u) |
121 ((stream_bitset & (~1u)) << (GRPC_MESSAGE_COMPRESS_ALGORITHMS_COUNT - 1));
122 return message_bitset | offset_stream_bitset;
123 }
124
grpc_compression_algorithm_from_message_stream_compression_algorithm(grpc_compression_algorithm * algorithm,grpc_message_compression_algorithm message_algorithm,grpc_stream_compression_algorithm stream_algorithm)125 int grpc_compression_algorithm_from_message_stream_compression_algorithm(
126 grpc_compression_algorithm* algorithm,
127 grpc_message_compression_algorithm message_algorithm,
128 grpc_stream_compression_algorithm stream_algorithm) {
129 if (message_algorithm != GRPC_MESSAGE_COMPRESS_NONE &&
130 stream_algorithm != GRPC_STREAM_COMPRESS_NONE) {
131 *algorithm = GRPC_COMPRESS_NONE;
132 return 0;
133 }
134 if (message_algorithm == GRPC_MESSAGE_COMPRESS_NONE) {
135 switch (stream_algorithm) {
136 case GRPC_STREAM_COMPRESS_NONE:
137 *algorithm = GRPC_COMPRESS_NONE;
138 return 1;
139 case GRPC_STREAM_COMPRESS_GZIP:
140 *algorithm = GRPC_COMPRESS_STREAM_GZIP;
141 return 1;
142 default:
143 *algorithm = GRPC_COMPRESS_NONE;
144 return 0;
145 }
146 } else {
147 switch (message_algorithm) {
148 case GRPC_MESSAGE_COMPRESS_NONE:
149 *algorithm = GRPC_COMPRESS_NONE;
150 return 1;
151 case GRPC_MESSAGE_COMPRESS_DEFLATE:
152 *algorithm = GRPC_COMPRESS_DEFLATE;
153 return 1;
154 case GRPC_MESSAGE_COMPRESS_GZIP:
155 *algorithm = GRPC_COMPRESS_GZIP;
156 return 1;
157 default:
158 *algorithm = GRPC_COMPRESS_NONE;
159 return 0;
160 }
161 }
162 return 0;
163 }
164
165 /* Interfaces for message compression. */
166
grpc_message_compression_algorithm_name(grpc_message_compression_algorithm algorithm,const char ** name)167 int grpc_message_compression_algorithm_name(
168 grpc_message_compression_algorithm algorithm, const char** name) {
169 GRPC_API_TRACE(
170 "grpc_message_compression_algorithm_parse(algorithm=%d, name=%p)", 2,
171 ((int)algorithm, name));
172 switch (algorithm) {
173 case GRPC_MESSAGE_COMPRESS_NONE:
174 *name = "identity";
175 return 1;
176 case GRPC_MESSAGE_COMPRESS_DEFLATE:
177 *name = "deflate";
178 return 1;
179 case GRPC_MESSAGE_COMPRESS_GZIP:
180 *name = "gzip";
181 return 1;
182 case GRPC_MESSAGE_COMPRESS_ALGORITHMS_COUNT:
183 return 0;
184 }
185 return 0;
186 }
187
188 /* TODO(dgq): Add the ability to specify parameters to the individual
189 * compression algorithms */
grpc_message_compression_algorithm_for_level(grpc_compression_level level,uint32_t accepted_encodings)190 grpc_message_compression_algorithm grpc_message_compression_algorithm_for_level(
191 grpc_compression_level level, uint32_t accepted_encodings) {
192 GRPC_API_TRACE("grpc_message_compression_algorithm_for_level(level=%d)", 1,
193 ((int)level));
194 if (level > GRPC_COMPRESS_LEVEL_HIGH) {
195 gpr_log(GPR_ERROR, "Unknown message compression level %d.",
196 static_cast<int>(level));
197 abort();
198 }
199
200 const size_t num_supported =
201 GPR_BITCOUNT(accepted_encodings) - 1; /* discard NONE */
202 if (level == GRPC_COMPRESS_LEVEL_NONE || num_supported == 0) {
203 return GRPC_MESSAGE_COMPRESS_NONE;
204 }
205
206 GPR_ASSERT(level > 0);
207
208 /* Establish a "ranking" or compression algorithms in increasing order of
209 * compression.
210 * This is simplistic and we will probably want to introduce other dimensions
211 * in the future (cpu/memory cost, etc). */
212 const grpc_message_compression_algorithm algos_ranking[] = {
213 GRPC_MESSAGE_COMPRESS_GZIP, GRPC_MESSAGE_COMPRESS_DEFLATE};
214
215 /* intersect algos_ranking with the supported ones keeping the ranked order */
216 grpc_message_compression_algorithm
217 sorted_supported_algos[GRPC_MESSAGE_COMPRESS_ALGORITHMS_COUNT];
218 size_t algos_supported_idx = 0;
219 for (size_t i = 0; i < GPR_ARRAY_SIZE(algos_ranking); i++) {
220 const grpc_message_compression_algorithm alg = algos_ranking[i];
221 for (size_t j = 0; j < num_supported; j++) {
222 if (GPR_BITGET(accepted_encodings, alg) == 1) {
223 /* if \a alg in supported */
224 sorted_supported_algos[algos_supported_idx++] = alg;
225 break;
226 }
227 }
228 if (algos_supported_idx == num_supported) break;
229 }
230
231 switch (level) {
232 case GRPC_COMPRESS_LEVEL_NONE:
233 abort(); /* should have been handled already */
234 case GRPC_COMPRESS_LEVEL_LOW:
235 return sorted_supported_algos[0];
236 case GRPC_COMPRESS_LEVEL_MED:
237 return sorted_supported_algos[num_supported / 2];
238 case GRPC_COMPRESS_LEVEL_HIGH:
239 return sorted_supported_algos[num_supported - 1];
240 default:
241 abort();
242 };
243 }
244
grpc_message_compression_algorithm_parse(grpc_slice value,grpc_message_compression_algorithm * algorithm)245 int grpc_message_compression_algorithm_parse(
246 grpc_slice value, grpc_message_compression_algorithm* algorithm) {
247 if (grpc_slice_eq(value, GRPC_MDSTR_IDENTITY)) {
248 *algorithm = GRPC_MESSAGE_COMPRESS_NONE;
249 return 1;
250 } else if (grpc_slice_eq(value, GRPC_MDSTR_DEFLATE)) {
251 *algorithm = GRPC_MESSAGE_COMPRESS_DEFLATE;
252 return 1;
253 } else if (grpc_slice_eq(value, GRPC_MDSTR_GZIP)) {
254 *algorithm = GRPC_MESSAGE_COMPRESS_GZIP;
255 return 1;
256 } else {
257 return 0;
258 }
259 return 0;
260 }
261
262 /* Interfaces for stream compression. */
263
grpc_stream_compression_algorithm_parse(grpc_slice value,grpc_stream_compression_algorithm * algorithm)264 int grpc_stream_compression_algorithm_parse(
265 grpc_slice value, grpc_stream_compression_algorithm* algorithm) {
266 if (grpc_slice_eq(value, GRPC_MDSTR_IDENTITY)) {
267 *algorithm = GRPC_STREAM_COMPRESS_NONE;
268 return 1;
269 } else if (grpc_slice_eq(value, GRPC_MDSTR_GZIP)) {
270 *algorithm = GRPC_STREAM_COMPRESS_GZIP;
271 return 1;
272 } else {
273 return 0;
274 }
275 return 0;
276 }
277