• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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