blob: 065fe258dc84087c0701fff3c2af32cdd4677245 [file] [log] [blame]
David Garcia Quintas55b4ea12015-06-16 14:27:32 -07001/*
2 *
3 * Copyright 2015, Google Inc.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above
13 * copyright notice, this list of conditions and the following disclaimer
14 * in the documentation and/or other materials provided with the
15 * distribution.
16 * * Neither the name of Google Inc. nor the names of its
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 */
33
David Garcia Quintasd16af0e2015-06-22 22:39:21 -070034#include <assert.h>
David Garcia Quintas55b4ea12015-06-16 14:27:32 -070035#include <string.h>
36
David Garcia Quintas55b4ea12015-06-16 14:27:32 -070037#include <grpc/compression.h>
David Garcia Quintase091af82015-07-15 21:37:02 -070038#include <grpc/support/alloc.h>
David Garcia Quintas55b4ea12015-06-16 14:27:32 -070039#include <grpc/support/log.h>
40#include <grpc/support/slice_buffer.h>
41
David Garcia Quintas20afd462015-07-06 23:01:39 -070042#include "src/core/channel/compress_filter.h"
43#include "src/core/channel/channel_args.h"
44#include "src/core/compression/message_compress.h"
David Garcia Quintase091af82015-07-15 21:37:02 -070045#include "src/core/support/string.h"
David Garcia Quintas20afd462015-07-06 23:01:39 -070046
David Garcia Quintas55b4ea12015-06-16 14:27:32 -070047typedef struct call_data {
David Garcia Quintas7c4fdb52015-07-17 14:21:15 -070048 gpr_slice_buffer slices; /**< Buffers up input slices to be compressed */
David Garcia Quintasd16af0e2015-06-22 22:39:21 -070049 grpc_linked_mdelem compression_algorithm_storage;
David Garcia Quintase091af82015-07-15 21:37:02 -070050 grpc_linked_mdelem accept_encoding_storage;
David Garcia Quintas7c4fdb52015-07-17 14:21:15 -070051 int remaining_slice_bytes; /**< Input data to be read, as per BEGIN_MESSAGE */
52 int written_initial_metadata; /**< Already processed initial md? */
53 /** Compression algorithm we'll try to use. It may be given by incoming
54 * metadata, or by the channel's default compression settings. */
David Garcia Quintasd16af0e2015-06-22 22:39:21 -070055 grpc_compression_algorithm compression_algorithm;
David Garcia Quintas7c4fdb52015-07-17 14:21:15 -070056 /** If true, contents of \a compression_algorithm are authoritative */
57 int has_compression_algorithm;
David Garcia Quintas55b4ea12015-06-16 14:27:32 -070058} call_data;
59
60typedef struct channel_data {
David Garcia Quintas7c4fdb52015-07-17 14:21:15 -070061 /** Metadata key for the incoming (requested) compression algorithm */
David Garcia Quintasd7d9ce22015-06-30 23:29:03 -070062 grpc_mdstr *mdstr_request_compression_algorithm_key;
David Garcia Quintas7c4fdb52015-07-17 14:21:15 -070063 /** Metadata key for the outgoing (used) compression algorithm */
David Garcia Quintasd7d9ce22015-06-30 23:29:03 -070064 grpc_mdstr *mdstr_outgoing_compression_algorithm_key;
David Garcia Quintas39a6de22015-07-19 21:18:03 -070065 /** Metadata key for the accepted encodings */
David Garcia Quintase091af82015-07-15 21:37:02 -070066 grpc_mdstr *mdstr_compression_capabilities_key;
David Garcia Quintas7c4fdb52015-07-17 14:21:15 -070067 /** Precomputed metadata elements for all available compression algorithms */
David Garcia Quintasd16af0e2015-06-22 22:39:21 -070068 grpc_mdelem *mdelem_compression_algorithms[GRPC_COMPRESS_ALGORITHMS_COUNT];
David Garcia Quintas39a6de22015-07-19 21:18:03 -070069 /** Precomputed metadata elements for the accepted encodings */
David Garcia Quintase091af82015-07-15 21:37:02 -070070 grpc_mdelem *mdelem_accept_encoding;
David Garcia Quintas7c4fdb52015-07-17 14:21:15 -070071 /** The default, channel-level, compression algorithm */
David Garcia Quintasd16af0e2015-06-22 22:39:21 -070072 grpc_compression_algorithm default_compression_algorithm;
David Garcia Quintasbeac88c2015-08-10 13:39:52 -070073 /** Compression options for the channel */
74 grpc_compression_options compression_options;
David Garcia Quintas55b4ea12015-06-16 14:27:32 -070075} channel_data;
76
David Garcia Quintasf74a49e2015-06-18 17:22:45 -070077/** Compress \a slices in place using \a algorithm. Returns 1 if compression did
78 * actually happen, 0 otherwise (for example if the compressed output size was
79 * larger than the raw input).
80 *
81 * Returns 1 if the data was actually compress and 0 otherwise. */
82static int compress_send_sb(grpc_compression_algorithm algorithm,
David Garcia Quintas55b4ea12015-06-16 14:27:32 -070083 gpr_slice_buffer *slices) {
David Garcia Quintasf74a49e2015-06-18 17:22:45 -070084 int did_compress;
David Garcia Quintas55b4ea12015-06-16 14:27:32 -070085 gpr_slice_buffer tmp;
86 gpr_slice_buffer_init(&tmp);
David Garcia Quintasf74a49e2015-06-18 17:22:45 -070087 did_compress = grpc_msg_compress(algorithm, slices, &tmp);
David Garcia Quintas4e403362015-07-01 16:45:34 -070088 if (did_compress) {
89 gpr_slice_buffer_swap(slices, &tmp);
90 }
David Garcia Quintas55b4ea12015-06-16 14:27:32 -070091 gpr_slice_buffer_destroy(&tmp);
David Garcia Quintasf74a49e2015-06-18 17:22:45 -070092 return did_compress;
David Garcia Quintas55b4ea12015-06-16 14:27:32 -070093}
94
David Garcia Quintasd16af0e2015-06-22 22:39:21 -070095/** For each \a md element from the incoming metadata, filter out the entry for
David Garcia Quintasd7d9ce22015-06-30 23:29:03 -070096 * "grpc-encoding", using its value to populate the call data's
David Garcia Quintasd16af0e2015-06-22 22:39:21 -070097 * compression_algorithm field. */
98static grpc_mdelem* compression_md_filter(void *user_data, grpc_mdelem *md) {
99 grpc_call_element *elem = user_data;
100 call_data *calld = elem->call_data;
101 channel_data *channeld = elem->channel_data;
102
David Garcia Quintasd7d9ce22015-06-30 23:29:03 -0700103 if (md->key == channeld->mdstr_request_compression_algorithm_key) {
David Garcia Quintasfc0fa332015-06-25 18:11:07 -0700104 const char *md_c_str = grpc_mdstr_as_c_string(md->value);
David Garcia Quintas1c604fd2015-07-21 16:22:58 -0700105 if (!grpc_compression_algorithm_parse(md_c_str, strlen(md_c_str),
David Garcia Quintasfc0fa332015-06-25 18:11:07 -0700106 &calld->compression_algorithm)) {
David Garcia Quintasbeac88c2015-08-10 13:39:52 -0700107 gpr_log(GPR_ERROR,
108 "Invalid compression algorithm: '%s' (unknown). Ignoring.",
109 md_c_str);
110 calld->compression_algorithm = GRPC_COMPRESS_NONE;
111 }
112 if (grpc_compression_options_is_algorithm_enabled(
113 &channeld->compression_options, calld->compression_algorithm) == 0)
114 {
115 gpr_log(GPR_ERROR,
116 "Invalid compression algorithm: '%s' (previously disabled). "
117 "Ignoring.",
David Garcia Quintasfc0fa332015-06-25 18:11:07 -0700118 md_c_str);
119 calld->compression_algorithm = GRPC_COMPRESS_NONE;
120 }
David Garcia Quintasd16af0e2015-06-22 22:39:21 -0700121 calld->has_compression_algorithm = 1;
122 return NULL;
123 }
124
125 return md;
126}
127
128static int skip_compression(channel_data *channeld, call_data *calld) {
David Garcia Quintasfc0fa332015-06-25 18:11:07 -0700129 if (calld->has_compression_algorithm) {
130 if (calld->compression_algorithm == GRPC_COMPRESS_NONE) {
131 return 1;
132 }
133 return 0; /* we have an actual call-specific algorithm */
David Garcia Quintasd16af0e2015-06-22 22:39:21 -0700134 }
135 /* no per-call compression override */
136 return channeld->default_compression_algorithm == GRPC_COMPRESS_NONE;
137}
138
David Garcia Quintas658b6082015-07-15 13:46:00 -0700139/** Assembles a new grpc_stream_op_buffer with the compressed slices, modifying
140 * the associated GRPC_OP_BEGIN_MESSAGE accordingly (new compressed length,
141 * flags indicating compression is in effect) and replaces \a send_ops with it.
142 * */
David Garcia Quintasa01f7a42015-07-08 00:16:50 -0700143static void finish_compressed_sopb(grpc_stream_op_buffer *send_ops,
144 grpc_call_element *elem) {
David Garcia Quintas20a35382015-07-10 17:48:22 -0700145 size_t i;
David Garcia Quintas20afd462015-07-06 23:01:39 -0700146 call_data *calld = elem->call_data;
David Garcia Quintas20a35382015-07-10 17:48:22 -0700147 int new_slices_added = 0; /* GPR_FALSE */
David Garcia Quintas658b6082015-07-15 13:46:00 -0700148 grpc_metadata_batch metadata;
149 grpc_stream_op_buffer new_send_ops;
David Garcia Quintas20a35382015-07-10 17:48:22 -0700150 grpc_sopb_init(&new_send_ops);
David Garcia Quintas20afd462015-07-06 23:01:39 -0700151
David Garcia Quintas20a35382015-07-10 17:48:22 -0700152 for (i = 0; i < send_ops->nops; i++) {
David Garcia Quintas20afd462015-07-06 23:01:39 -0700153 grpc_stream_op *sop = &send_ops->ops[i];
154 switch (sop->type) {
155 case GRPC_OP_BEGIN_MESSAGE:
David Garcia Quintas20a35382015-07-10 17:48:22 -0700156 grpc_sopb_add_begin_message(
157 &new_send_ops, calld->slices.length,
158 sop->data.begin_message.flags | GRPC_WRITE_INTERNAL_COMPRESS);
David Garcia Quintas20afd462015-07-06 23:01:39 -0700159 break;
David Garcia Quintas20afd462015-07-06 23:01:39 -0700160 case GRPC_OP_SLICE:
David Garcia Quintas658b6082015-07-15 13:46:00 -0700161 /* Once we reach the slices section of the original buffer, simply add
162 * all the new (compressed) slices. We obviously want to do this only
163 * once, hence the "new_slices_added" guard. */
David Garcia Quintas20a35382015-07-10 17:48:22 -0700164 if (!new_slices_added) {
165 size_t j;
166 for (j = 0; j < calld->slices.count; ++j) {
167 grpc_sopb_add_slice(&new_send_ops,
168 gpr_slice_ref(calld->slices.slices[j]));
169 }
170 new_slices_added = 1; /* GPR_TRUE */
David Garcia Quintas20afd462015-07-06 23:01:39 -0700171 }
David Garcia Quintasa01f7a42015-07-08 00:16:50 -0700172 break;
David Garcia Quintasd317e752015-07-15 00:09:27 -0700173 case GRPC_OP_METADATA:
David Garcia Quintas658b6082015-07-15 13:46:00 -0700174 /* move the metadata to the new buffer. */
175 grpc_metadata_batch_move(&metadata, &sop->data.metadata);
176 grpc_sopb_add_metadata(&new_send_ops, metadata);
David Garcia Quintasd317e752015-07-15 00:09:27 -0700177 break;
David Garcia Quintas20afd462015-07-06 23:01:39 -0700178 case GRPC_NO_OP:
David Garcia Quintasa01f7a42015-07-08 00:16:50 -0700179 break;
David Garcia Quintas20afd462015-07-06 23:01:39 -0700180 }
181 }
David Garcia Quintas20a35382015-07-10 17:48:22 -0700182 grpc_sopb_swap(send_ops, &new_send_ops);
183 grpc_sopb_destroy(&new_send_ops);
David Garcia Quintas20afd462015-07-06 23:01:39 -0700184}
185
David Garcia Quintas7c4fdb52015-07-17 14:21:15 -0700186/** Filter's "main" function, called for any incoming grpc_transport_stream_op
187 * instance that holds a non-zero number of send operations, accesible to this
188 * function in \a send_ops. */
David Garcia Quintas55b4ea12015-06-16 14:27:32 -0700189static void process_send_ops(grpc_call_element *elem,
190 grpc_stream_op_buffer *send_ops) {
191 call_data *calld = elem->call_data;
192 channel_data *channeld = elem->channel_data;
David Garcia Quintas20afd462015-07-06 23:01:39 -0700193 size_t i;
David Garcia Quintasd16af0e2015-06-22 22:39:21 -0700194 int did_compress = 0;
David Garcia Quintasf74a49e2015-06-18 17:22:45 -0700195
David Garcia Quintas518e3fe2015-07-21 15:49:42 -0700196 /* In streaming calls, we need to reset the previously accumulated slices */
197 gpr_slice_buffer_reset_and_unref(&calld->slices);
David Garcia Quintas55b4ea12015-06-16 14:27:32 -0700198 for (i = 0; i < send_ops->nops; ++i) {
199 grpc_stream_op *sop = &send_ops->ops[i];
200 switch (sop->type) {
201 case GRPC_OP_BEGIN_MESSAGE:
David Garcia Quintas658b6082015-07-15 13:46:00 -0700202 /* buffer up slices until we've processed all the expected ones (as
203 * given by GRPC_OP_BEGIN_MESSAGE) */
David Garcia Quintas55b4ea12015-06-16 14:27:32 -0700204 calld->remaining_slice_bytes = sop->data.begin_message.length;
David Garcia Quintasd16af0e2015-06-22 22:39:21 -0700205 if (sop->data.begin_message.flags & GRPC_WRITE_NO_COMPRESS) {
206 calld->has_compression_algorithm = 1; /* GPR_TRUE */
207 calld->compression_algorithm = GRPC_COMPRESS_NONE;
208 }
209 break;
210 case GRPC_OP_METADATA:
David Garcia Quintasd317e752015-07-15 00:09:27 -0700211 if (!calld->written_initial_metadata) {
212 /* Parse incoming request for compression. If any, it'll be available
213 * at calld->compression_algorithm */
214 grpc_metadata_batch_filter(&(sop->data.metadata),
215 compression_md_filter, elem);
216 if (!calld->has_compression_algorithm) {
217 /* If no algorithm was found in the metadata and we aren't
218 * exceptionally skipping compression, fall back to the channel
219 * default */
220 calld->compression_algorithm =
221 channeld->default_compression_algorithm;
222 calld->has_compression_algorithm = 1; /* GPR_TRUE */
223 }
David Garcia Quintase091af82015-07-15 21:37:02 -0700224 /* hint compression algorithm */
Craig Tiller6159c072015-07-22 17:01:54 -0700225 grpc_metadata_batch_add_tail(
David Garcia Quintasd317e752015-07-15 00:09:27 -0700226 &(sop->data.metadata), &calld->compression_algorithm_storage,
David Garcia Quintasc0a09012015-07-20 01:27:47 -0700227 GRPC_MDELEM_REF(channeld->mdelem_compression_algorithms
David Garcia Quintasd317e752015-07-15 00:09:27 -0700228 [calld->compression_algorithm]));
David Garcia Quintase091af82015-07-15 21:37:02 -0700229
230 /* convey supported compression algorithms */
231 grpc_metadata_batch_add_head(
232 &(sop->data.metadata), &calld->accept_encoding_storage,
David Garcia Quintasc0a09012015-07-20 01:27:47 -0700233 GRPC_MDELEM_REF(channeld->mdelem_accept_encoding));
David Garcia Quintase091af82015-07-15 21:37:02 -0700234
David Garcia Quintasd317e752015-07-15 00:09:27 -0700235 calld->written_initial_metadata = 1; /* GPR_TRUE */
David Garcia Quintasd16af0e2015-06-22 22:39:21 -0700236 }
David Garcia Quintas55b4ea12015-06-16 14:27:32 -0700237 break;
238 case GRPC_OP_SLICE:
David Garcia Quintasd317e752015-07-15 00:09:27 -0700239 if (skip_compression(channeld, calld)) continue;
David Garcia Quintas55b4ea12015-06-16 14:27:32 -0700240 GPR_ASSERT(calld->remaining_slice_bytes > 0);
David Garcia Quintas658b6082015-07-15 13:46:00 -0700241 /* Increase input ref count, gpr_slice_buffer_add takes ownership. */
David Garcia Quintas4e403362015-07-01 16:45:34 -0700242 gpr_slice_buffer_add(&calld->slices, gpr_slice_ref(sop->data.slice));
David Garcia Quintas55b4ea12015-06-16 14:27:32 -0700243 calld->remaining_slice_bytes -= GPR_SLICE_LENGTH(sop->data.slice);
244 if (calld->remaining_slice_bytes == 0) {
David Garcia Quintasd16af0e2015-06-22 22:39:21 -0700245 did_compress =
246 compress_send_sb(calld->compression_algorithm, &calld->slices);
247 }
248 break;
249 case GRPC_NO_OP:
David Garcia Quintasa21e2c82015-07-10 00:15:36 -0700250 break;
David Garcia Quintasd16af0e2015-06-22 22:39:21 -0700251 }
252 }
253
David Garcia Quintas20afd462015-07-06 23:01:39 -0700254 /* Modify the send_ops stream_op_buffer depending on whether compression was
255 * carried out */
David Garcia Quintasa01f7a42015-07-08 00:16:50 -0700256 if (did_compress) {
257 finish_compressed_sopb(send_ops, elem);
David Garcia Quintasa01f7a42015-07-08 00:16:50 -0700258 }
David Garcia Quintas55b4ea12015-06-16 14:27:32 -0700259}
260
261/* Called either:
262 - in response to an API call (or similar) from above, to send something
263 - a network event (or similar) from below, to receive something
264 op contains type and call direction information, in addition to the data
265 that is being sent or received. */
David Garcia Quintas17bb6492015-07-08 15:16:22 -0700266static void compress_start_transport_stream_op(grpc_call_element *elem,
267 grpc_transport_stream_op *op) {
David Garcia Quintas55b4ea12015-06-16 14:27:32 -0700268 if (op->send_ops && op->send_ops->nops > 0) {
269 process_send_ops(elem, op->send_ops);
270 }
271
272 /* pass control down the stack */
273 grpc_call_next_op(elem, op);
274}
275
David Garcia Quintas55b4ea12015-06-16 14:27:32 -0700276/* Constructor for call_data */
277static void init_call_elem(grpc_call_element *elem,
278 const void *server_transport_data,
David Garcia Quintas17bb6492015-07-08 15:16:22 -0700279 grpc_transport_stream_op *initial_op) {
David Garcia Quintas55b4ea12015-06-16 14:27:32 -0700280 /* grab pointers to our data from the call element */
281 call_data *calld = elem->call_data;
282
283 /* initialize members */
284 gpr_slice_buffer_init(&calld->slices);
David Garcia Quintasd16af0e2015-06-22 22:39:21 -0700285 calld->has_compression_algorithm = 0;
David Garcia Quintasd317e752015-07-15 00:09:27 -0700286 calld->written_initial_metadata = 0; /* GPR_FALSE */
David Garcia Quintas55b4ea12015-06-16 14:27:32 -0700287
288 if (initial_op) {
289 if (initial_op->send_ops && initial_op->send_ops->nops > 0) {
290 process_send_ops(elem, initial_op->send_ops);
291 }
292 }
293}
294
295/* Destructor for call_data */
296static void destroy_call_elem(grpc_call_element *elem) {
297 /* grab pointers to our data from the call element */
298 call_data *calld = elem->call_data;
299 gpr_slice_buffer_destroy(&calld->slices);
300}
301
302/* Constructor for channel_data */
David Garcia Quintas17bb6492015-07-08 15:16:22 -0700303static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master,
David Garcia Quintas55b4ea12015-06-16 14:27:32 -0700304 const grpc_channel_args *args, grpc_mdctx *mdctx,
305 int is_first, int is_last) {
306 channel_data *channeld = elem->channel_data;
David Garcia Quintasd16af0e2015-06-22 22:39:21 -0700307 grpc_compression_algorithm algo_idx;
David Garcia Quintase091af82015-07-15 21:37:02 -0700308 const char* supported_algorithms_names[GRPC_COMPRESS_ALGORITHMS_COUNT-1];
309 char *accept_encoding_str;
310 size_t accept_encoding_str_len;
David Garcia Quintasf74a49e2015-06-18 17:22:45 -0700311
David Garcia Quintasbeac88c2015-08-10 13:39:52 -0700312 grpc_compression_options_init(&channeld->compression_options);
313 channeld->compression_options.enabled_algorithms_bitset =
314 grpc_channel_args_compression_algorithm_get_states(args);
315
David Garcia Quintasd16af0e2015-06-22 22:39:21 -0700316 channeld->default_compression_algorithm =
David Garcia Quintascadbf222015-07-17 15:33:13 -0700317 grpc_channel_args_get_compression_algorithm(args);
David Garcia Quintasbeac88c2015-08-10 13:39:52 -0700318 /* Make sure the default isn't disabled. */
319 GPR_ASSERT(grpc_compression_options_is_algorithm_enabled(
320 &channeld->compression_options, channeld->default_compression_algorithm));
321 channeld->compression_options.default_compression_algorithm =
322 channeld->default_compression_algorithm;
David Garcia Quintasf74a49e2015-06-18 17:22:45 -0700323
David Garcia Quintasd7d9ce22015-06-30 23:29:03 -0700324 channeld->mdstr_request_compression_algorithm_key =
Craig Tiller6999c092015-07-22 08:14:12 -0700325 grpc_mdstr_from_string(mdctx, GRPC_COMPRESS_REQUEST_ALGORITHM_KEY, 0);
David Garcia Quintasd7d9ce22015-06-30 23:29:03 -0700326
327 channeld->mdstr_outgoing_compression_algorithm_key =
Craig Tiller6999c092015-07-22 08:14:12 -0700328 grpc_mdstr_from_string(mdctx, "grpc-encoding", 0);
David Garcia Quintasd16af0e2015-06-22 22:39:21 -0700329
David Garcia Quintase091af82015-07-15 21:37:02 -0700330 channeld->mdstr_compression_capabilities_key =
David Garcia Quintas10494fc2015-08-09 08:52:47 -0700331 grpc_mdstr_from_string(mdctx, "grpc-accept-encoding", 0);
David Garcia Quintase091af82015-07-15 21:37:02 -0700332
David Garcia Quintasd16af0e2015-06-22 22:39:21 -0700333 for (algo_idx = 0; algo_idx < GRPC_COMPRESS_ALGORITHMS_COUNT; ++algo_idx) {
Craig Tiller6999c092015-07-22 08:14:12 -0700334 char *algorithm_name;
David Garcia Quintasbeac88c2015-08-10 13:39:52 -0700335 /* skip disabled algorithms */
336 if (grpc_compression_options_is_algorithm_enabled(
337 &channeld->compression_options, algo_idx) == 0) {
338 continue;
339 }
Craig Tiller6999c092015-07-22 08:14:12 -0700340 GPR_ASSERT(grpc_compression_algorithm_name(algo_idx, &algorithm_name) != 0);
David Garcia Quintasd16af0e2015-06-22 22:39:21 -0700341 channeld->mdelem_compression_algorithms[algo_idx] =
342 grpc_mdelem_from_metadata_strings(
David Garcia Quintasd7d9ce22015-06-30 23:29:03 -0700343 mdctx,
David Garcia Quintasc0a09012015-07-20 01:27:47 -0700344 GRPC_MDSTR_REF(channeld->mdstr_outgoing_compression_algorithm_key),
Craig Tiller6999c092015-07-22 08:14:12 -0700345 grpc_mdstr_from_string(mdctx, algorithm_name, 0));
David Garcia Quintase091af82015-07-15 21:37:02 -0700346 if (algo_idx > 0) {
David Garcia Quintas10494fc2015-08-09 08:52:47 -0700347 supported_algorithms_names[algo_idx-1] = algorithm_name;
David Garcia Quintase091af82015-07-15 21:37:02 -0700348 }
David Garcia Quintasd16af0e2015-06-22 22:39:21 -0700349 }
David Garcia Quintas55b4ea12015-06-16 14:27:32 -0700350
David Garcia Quintasc0a09012015-07-20 01:27:47 -0700351 /* TODO(dgq): gpr_strjoin_sep could be made to work with statically allocated
352 * arrays, as to avoid the heap allocs */
David Garcia Quintase091af82015-07-15 21:37:02 -0700353 accept_encoding_str =
354 gpr_strjoin_sep(supported_algorithms_names,
355 GPR_ARRAY_SIZE(supported_algorithms_names),
356 ", ",
357 &accept_encoding_str_len);
358
359 channeld->mdelem_accept_encoding =
360 grpc_mdelem_from_metadata_strings(
361 mdctx,
David Garcia Quintasc0a09012015-07-20 01:27:47 -0700362 GRPC_MDSTR_REF(channeld->mdstr_compression_capabilities_key),
David Garcia Quintas10494fc2015-08-09 08:52:47 -0700363 grpc_mdstr_from_string(mdctx, accept_encoding_str, 0));
David Garcia Quintase091af82015-07-15 21:37:02 -0700364 gpr_free(accept_encoding_str);
365
David Garcia Quintas55b4ea12015-06-16 14:27:32 -0700366 GPR_ASSERT(!is_last);
367}
368
369/* Destructor for channel data */
370static void destroy_channel_elem(grpc_channel_element *elem) {
David Garcia Quintasf74a49e2015-06-18 17:22:45 -0700371 channel_data *channeld = elem->channel_data;
David Garcia Quintasd16af0e2015-06-22 22:39:21 -0700372 grpc_compression_algorithm algo_idx;
373
David Garcia Quintasc0a09012015-07-20 01:27:47 -0700374 GRPC_MDSTR_UNREF(channeld->mdstr_request_compression_algorithm_key);
375 GRPC_MDSTR_UNREF(channeld->mdstr_outgoing_compression_algorithm_key);
376 GRPC_MDSTR_UNREF(channeld->mdstr_compression_capabilities_key);
David Garcia Quintasd16af0e2015-06-22 22:39:21 -0700377 for (algo_idx = 0; algo_idx < GRPC_COMPRESS_ALGORITHMS_COUNT;
378 ++algo_idx) {
David Garcia Quintasc0a09012015-07-20 01:27:47 -0700379 GRPC_MDELEM_UNREF(channeld->mdelem_compression_algorithms[algo_idx]);
David Garcia Quintasd16af0e2015-06-22 22:39:21 -0700380 }
David Garcia Quintasc0a09012015-07-20 01:27:47 -0700381 GRPC_MDELEM_UNREF(channeld->mdelem_accept_encoding);
David Garcia Quintas55b4ea12015-06-16 14:27:32 -0700382}
383
David Garcia Quintasd317e752015-07-15 00:09:27 -0700384const grpc_channel_filter grpc_compress_filter = {
385 compress_start_transport_stream_op,
386 grpc_channel_next_op,
387 sizeof(call_data),
388 init_call_elem,
389 destroy_call_elem,
390 sizeof(channel_data),
391 init_channel_elem,
392 destroy_channel_elem,
Craig Tiller1b22b9d2015-07-20 13:42:22 -0700393 grpc_call_next_get_peer,
David Garcia Quintasd317e752015-07-15 00:09:27 -0700394 "compress"};