blob: c051e28864fe5c3278402ec41faa0e98ae11d329 [file] [log] [blame]
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001/*
2 *
Jan Tattermusch7897ae92017-06-07 22:57:36 +02003 * Copyright 2015 gRPC authors.
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08004 *
Jan Tattermusch7897ae92017-06-07 22:57:36 +02005 * 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
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08008 *
Jan Tattermusch7897ae92017-06-07 22:57:36 +02009 * http://www.apache.org/licenses/LICENSE-2.0
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080010 *
Jan Tattermusch7897ae92017-06-07 22:57:36 +020011 * 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.
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080016 *
17 */
18
Craig Tiller9533d042016-03-25 17:11:06 -070019#include "src/core/lib/compression/message_compress.h"
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080020
21#include <string.h>
22
23#include <grpc/support/alloc.h>
24#include <grpc/support/log.h>
25
26#include <zlib.h>
27
Craig Tillera59c16c2016-10-31 07:25:01 -070028#include "src/core/lib/slice/slice_internal.h"
29
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080030#define OUTPUT_BLOCK_SIZE 1024
31
Craig Tillera59c16c2016-10-31 07:25:01 -070032static int zlib_body(grpc_exec_ctx* exec_ctx, z_stream* zs,
33 grpc_slice_buffer* input, grpc_slice_buffer* output,
Craig Tillera82950e2015-09-22 12:33:20 -070034 int (*flate)(z_stream* zs, int flush)) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080035 int r;
36 int flush;
37 size_t i;
Craig Tiller423d6fd2017-04-12 13:15:45 -070038 grpc_slice outbuf = GRPC_SLICE_MALLOC(OUTPUT_BLOCK_SIZE);
Craig Tillera82950e2015-09-22 12:33:20 -070039 const uInt uint_max = ~(uInt)0;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080040
Craig Tiller618e67d2016-10-26 21:08:10 -070041 GPR_ASSERT(GRPC_SLICE_LENGTH(outbuf) <= uint_max);
42 zs->avail_out = (uInt)GRPC_SLICE_LENGTH(outbuf);
43 zs->next_out = GRPC_SLICE_START_PTR(outbuf);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080044 flush = Z_NO_FLUSH;
Craig Tillera82950e2015-09-22 12:33:20 -070045 for (i = 0; i < input->count; i++) {
46 if (i == input->count - 1) flush = Z_FINISH;
Craig Tiller618e67d2016-10-26 21:08:10 -070047 GPR_ASSERT(GRPC_SLICE_LENGTH(input->slices[i]) <= uint_max);
48 zs->avail_in = (uInt)GRPC_SLICE_LENGTH(input->slices[i]);
49 zs->next_in = GRPC_SLICE_START_PTR(input->slices[i]);
Craig Tillera82950e2015-09-22 12:33:20 -070050 do {
51 if (zs->avail_out == 0) {
Craig Tillerd41a4a72016-10-26 16:16:06 -070052 grpc_slice_buffer_add_indexed(output, outbuf);
Craig Tiller423d6fd2017-04-12 13:15:45 -070053 outbuf = GRPC_SLICE_MALLOC(OUTPUT_BLOCK_SIZE);
Craig Tiller618e67d2016-10-26 21:08:10 -070054 GPR_ASSERT(GRPC_SLICE_LENGTH(outbuf) <= uint_max);
55 zs->avail_out = (uInt)GRPC_SLICE_LENGTH(outbuf);
56 zs->next_out = GRPC_SLICE_START_PTR(outbuf);
Craig Tillera82950e2015-09-22 12:33:20 -070057 }
58 r = flate(zs, flush);
David Garcia Quintas5e0da582015-12-10 18:27:32 -080059 if (r < 0 && r != Z_BUF_ERROR /* not fatal */) {
60 gpr_log(GPR_INFO, "zlib error (%d)", r);
Craig Tillera82950e2015-09-22 12:33:20 -070061 goto error;
62 }
63 } while (zs->avail_out == 0);
64 if (zs->avail_in) {
65 gpr_log(GPR_INFO, "zlib: not all input consumed");
66 goto error;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080067 }
Craig Tillera82950e2015-09-22 12:33:20 -070068 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080069
Craig Tillera82950e2015-09-22 12:33:20 -070070 GPR_ASSERT(outbuf.refcount);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080071 outbuf.data.refcounted.length -= zs->avail_out;
Craig Tillerd41a4a72016-10-26 16:16:06 -070072 grpc_slice_buffer_add_indexed(output, outbuf);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080073
74 return 1;
75
76error:
Craig Tillera59c16c2016-10-31 07:25:01 -070077 grpc_slice_unref_internal(exec_ctx, outbuf);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080078 return 0;
79}
80
Craig Tiller620e9652015-12-14 12:02:50 -080081static void* zalloc_gpr(void* opaque, unsigned int items, unsigned int size) {
David Garcia Quintas0a087912015-12-09 10:46:14 -080082 return gpr_malloc(items * size);
83}
84
Craig Tiller620e9652015-12-14 12:02:50 -080085static void zfree_gpr(void* opaque, void* address) { gpr_free(address); }
David Garcia Quintas0a087912015-12-09 10:46:14 -080086
Craig Tillera59c16c2016-10-31 07:25:01 -070087static int zlib_compress(grpc_exec_ctx* exec_ctx, grpc_slice_buffer* input,
88 grpc_slice_buffer* output, int gzip) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080089 z_stream zs;
90 int r;
91 size_t i;
92 size_t count_before = output->count;
93 size_t length_before = output->length;
Craig Tillera82950e2015-09-22 12:33:20 -070094 memset(&zs, 0, sizeof(zs));
David Garcia Quintas0a087912015-12-09 10:46:14 -080095 zs.zalloc = zalloc_gpr;
96 zs.zfree = zfree_gpr;
Craig Tillera82950e2015-09-22 12:33:20 -070097 r = deflateInit2(&zs, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 15 | (gzip ? 16 : 0),
98 8, Z_DEFAULT_STRATEGY);
David Garcia Quintase9fa3112015-12-09 17:25:10 -080099 GPR_ASSERT(r == Z_OK);
Craig Tillera59c16c2016-10-31 07:25:01 -0700100 r = zlib_body(exec_ctx, &zs, input, output, deflate) &&
101 output->length < input->length;
Craig Tillera82950e2015-09-22 12:33:20 -0700102 if (!r) {
103 for (i = count_before; i < output->count; i++) {
Craig Tillera59c16c2016-10-31 07:25:01 -0700104 grpc_slice_unref_internal(exec_ctx, output->slices[i]);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800105 }
Craig Tillera82950e2015-09-22 12:33:20 -0700106 output->count = count_before;
107 output->length = length_before;
108 }
109 deflateEnd(&zs);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800110 return r;
111}
112
Craig Tillera59c16c2016-10-31 07:25:01 -0700113static int zlib_decompress(grpc_exec_ctx* exec_ctx, grpc_slice_buffer* input,
114 grpc_slice_buffer* output, int gzip) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800115 z_stream zs;
116 int r;
117 size_t i;
118 size_t count_before = output->count;
119 size_t length_before = output->length;
Craig Tillera82950e2015-09-22 12:33:20 -0700120 memset(&zs, 0, sizeof(zs));
David Garcia Quintas0a087912015-12-09 10:46:14 -0800121 zs.zalloc = zalloc_gpr;
122 zs.zfree = zfree_gpr;
Craig Tillera82950e2015-09-22 12:33:20 -0700123 r = inflateInit2(&zs, 15 | (gzip ? 16 : 0));
David Garcia Quintase9fa3112015-12-09 17:25:10 -0800124 GPR_ASSERT(r == Z_OK);
Craig Tillera59c16c2016-10-31 07:25:01 -0700125 r = zlib_body(exec_ctx, &zs, input, output, inflate);
Craig Tillera82950e2015-09-22 12:33:20 -0700126 if (!r) {
127 for (i = count_before; i < output->count; i++) {
Craig Tillera59c16c2016-10-31 07:25:01 -0700128 grpc_slice_unref_internal(exec_ctx, output->slices[i]);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800129 }
Craig Tillera82950e2015-09-22 12:33:20 -0700130 output->count = count_before;
131 output->length = length_before;
132 }
133 inflateEnd(&zs);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800134 return r;
135}
136
Craig Tillerd41a4a72016-10-26 16:16:06 -0700137static int copy(grpc_slice_buffer* input, grpc_slice_buffer* output) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800138 size_t i;
Craig Tillera82950e2015-09-22 12:33:20 -0700139 for (i = 0; i < input->count; i++) {
Craig Tillera59c16c2016-10-31 07:25:01 -0700140 grpc_slice_buffer_add(output, grpc_slice_ref_internal(input->slices[i]));
Craig Tillera82950e2015-09-22 12:33:20 -0700141 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800142 return 1;
143}
144
Craig Tillera59c16c2016-10-31 07:25:01 -0700145static int compress_inner(grpc_exec_ctx* exec_ctx,
146 grpc_compression_algorithm algorithm,
Craig Tillerd41a4a72016-10-26 16:16:06 -0700147 grpc_slice_buffer* input, grpc_slice_buffer* output) {
Craig Tillera82950e2015-09-22 12:33:20 -0700148 switch (algorithm) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800149 case GRPC_COMPRESS_NONE:
150 /* the fallback path always needs to be send uncompressed: we simply
151 rely on that here */
152 return 0;
153 case GRPC_COMPRESS_DEFLATE:
Craig Tillera59c16c2016-10-31 07:25:01 -0700154 return zlib_compress(exec_ctx, input, output, 0);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800155 case GRPC_COMPRESS_GZIP:
Craig Tillera59c16c2016-10-31 07:25:01 -0700156 return zlib_compress(exec_ctx, input, output, 1);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800157 case GRPC_COMPRESS_ALGORITHMS_COUNT:
158 break;
Craig Tillera82950e2015-09-22 12:33:20 -0700159 }
160 gpr_log(GPR_ERROR, "invalid compression algorithm %d", algorithm);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800161 return 0;
162}
163
Craig Tillera59c16c2016-10-31 07:25:01 -0700164int grpc_msg_compress(grpc_exec_ctx* exec_ctx,
165 grpc_compression_algorithm algorithm,
Craig Tillerd41a4a72016-10-26 16:16:06 -0700166 grpc_slice_buffer* input, grpc_slice_buffer* output) {
Craig Tillera59c16c2016-10-31 07:25:01 -0700167 if (!compress_inner(exec_ctx, algorithm, input, output)) {
Craig Tillera82950e2015-09-22 12:33:20 -0700168 copy(input, output);
169 return 0;
170 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800171 return 1;
172}
173
Craig Tillera59c16c2016-10-31 07:25:01 -0700174int grpc_msg_decompress(grpc_exec_ctx* exec_ctx,
175 grpc_compression_algorithm algorithm,
Craig Tillerd41a4a72016-10-26 16:16:06 -0700176 grpc_slice_buffer* input, grpc_slice_buffer* output) {
Craig Tillera82950e2015-09-22 12:33:20 -0700177 switch (algorithm) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800178 case GRPC_COMPRESS_NONE:
Craig Tillera82950e2015-09-22 12:33:20 -0700179 return copy(input, output);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800180 case GRPC_COMPRESS_DEFLATE:
Craig Tillera59c16c2016-10-31 07:25:01 -0700181 return zlib_decompress(exec_ctx, input, output, 0);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800182 case GRPC_COMPRESS_GZIP:
Craig Tillera59c16c2016-10-31 07:25:01 -0700183 return zlib_decompress(exec_ctx, input, output, 1);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800184 case GRPC_COMPRESS_ALGORITHMS_COUNT:
185 break;
Craig Tillera82950e2015-09-22 12:33:20 -0700186 }
187 gpr_log(GPR_ERROR, "invalid compression algorithm %d", algorithm);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800188 return 0;
Craig Tiller190d3602015-02-18 09:23:38 -0800189}