Line data Source code
1 : /*
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 :
34 : #include "src/core/compression/message_compress.h"
35 :
36 : #include <string.h>
37 :
38 : #include <grpc/support/alloc.h>
39 : #include <grpc/support/log.h>
40 :
41 : #include <zlib.h>
42 :
43 : #define OUTPUT_BLOCK_SIZE 1024
44 :
45 889 : static int zlib_body(z_stream* zs, gpr_slice_buffer* input,
46 : gpr_slice_buffer* output,
47 : int (*flate)(z_stream* zs, int flush)) {
48 : int r;
49 : int flush;
50 : size_t i;
51 889 : gpr_slice outbuf = gpr_slice_malloc(OUTPUT_BLOCK_SIZE);
52 889 : const uInt uint_max = ~(uInt)0;
53 :
54 889 : GPR_ASSERT(GPR_SLICE_LENGTH(outbuf) <= uint_max);
55 889 : zs->avail_out = (uInt)GPR_SLICE_LENGTH(outbuf);
56 889 : zs->next_out = GPR_SLICE_START_PTR(outbuf);
57 889 : flush = Z_NO_FLUSH;
58 6054 : for (i = 0; i < input->count; i++) {
59 5167 : if (i == input->count - 1) flush = Z_FINISH;
60 5167 : GPR_ASSERT(GPR_SLICE_LENGTH(input->slices[i]) <= uint_max);
61 5167 : zs->avail_in = (uInt)GPR_SLICE_LENGTH(input->slices[i]);
62 5167 : zs->next_in = GPR_SLICE_START_PTR(input->slices[i]);
63 : do {
64 17483 : if (zs->avail_out == 0) {
65 12316 : gpr_slice_buffer_add_indexed(output, outbuf);
66 12316 : outbuf = gpr_slice_malloc(OUTPUT_BLOCK_SIZE);
67 12316 : GPR_ASSERT(GPR_SLICE_LENGTH(outbuf) <= uint_max);
68 12316 : zs->avail_out = (uInt)GPR_SLICE_LENGTH(outbuf);
69 12316 : zs->next_out = GPR_SLICE_START_PTR(outbuf);
70 : }
71 17483 : r = flate(zs, flush);
72 17483 : if (r == Z_STREAM_ERROR) {
73 0 : gpr_log(GPR_INFO, "zlib: stream error");
74 0 : goto error;
75 : }
76 17483 : } while (zs->avail_out == 0);
77 5167 : if (zs->avail_in) {
78 2 : gpr_log(GPR_INFO, "zlib: not all input consumed");
79 2 : goto error;
80 : }
81 : }
82 :
83 887 : GPR_ASSERT(outbuf.refcount);
84 887 : outbuf.data.refcounted.length -= zs->avail_out;
85 887 : gpr_slice_buffer_add_indexed(output, outbuf);
86 :
87 887 : return 1;
88 :
89 : error:
90 2 : gpr_slice_unref(outbuf);
91 2 : return 0;
92 : }
93 :
94 4093 : static void *zalloc_gpr(void* opaque, unsigned int items, unsigned int size) {
95 4093 : return gpr_malloc(items * size);
96 : }
97 :
98 4093 : static void zfree_gpr(void* opaque, void *address) {
99 4093 : gpr_free(address);
100 4093 : }
101 :
102 795 : static int zlib_compress(gpr_slice_buffer* input, gpr_slice_buffer* output,
103 : int gzip) {
104 : z_stream zs;
105 : int r;
106 : size_t i;
107 795 : size_t count_before = output->count;
108 795 : size_t length_before = output->length;
109 795 : memset(&zs, 0, sizeof(zs));
110 795 : zs.zalloc = zalloc_gpr;
111 795 : zs.zfree = zfree_gpr;
112 795 : r = deflateInit2(&zs, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 15 | (gzip ? 16 : 0),
113 : 8, Z_DEFAULT_STRATEGY);
114 795 : if (r != Z_OK) {
115 0 : gpr_log(GPR_ERROR, "deflateInit2 returns %d", r);
116 0 : return 0;
117 : }
118 795 : r = zlib_body(&zs, input, output, deflate) && output->length < input->length;
119 795 : if (!r) {
120 1398 : for (i = count_before; i < output->count; i++) {
121 699 : gpr_slice_unref(output->slices[i]);
122 : }
123 699 : output->count = count_before;
124 699 : output->length = length_before;
125 : }
126 795 : deflateEnd(&zs);
127 795 : return r;
128 : }
129 :
130 94 : static int zlib_decompress(gpr_slice_buffer* input, gpr_slice_buffer* output,
131 : int gzip) {
132 : z_stream zs;
133 : int r;
134 : size_t i;
135 94 : size_t count_before = output->count;
136 94 : size_t length_before = output->length;
137 94 : memset(&zs, 0, sizeof(zs));
138 94 : zs.zalloc = zalloc_gpr;
139 94 : zs.zfree = zfree_gpr;
140 94 : r = inflateInit2(&zs, 15 | (gzip ? 16 : 0));
141 94 : if (r != Z_OK) {
142 0 : gpr_log(GPR_ERROR, "inflateInit2 returns %d", r);
143 0 : return 0;
144 : }
145 94 : r = zlib_body(&zs, input, output, inflate);
146 94 : if (!r) {
147 2 : for (i = count_before; i < output->count; i++) {
148 0 : gpr_slice_unref(output->slices[i]);
149 : }
150 2 : output->count = count_before;
151 2 : output->length = length_before;
152 : }
153 94 : inflateEnd(&zs);
154 94 : return r;
155 : }
156 :
157 749 : static int copy(gpr_slice_buffer* input, gpr_slice_buffer* output) {
158 : size_t i;
159 2100694 : for (i = 0; i < input->count; i++) {
160 2099945 : gpr_slice_buffer_add(output, gpr_slice_ref(input->slices[i]));
161 : }
162 749 : return 1;
163 : }
164 :
165 815 : static int compress_inner(grpc_compression_algorithm algorithm,
166 : gpr_slice_buffer* input, gpr_slice_buffer* output) {
167 815 : switch (algorithm) {
168 : case GRPC_COMPRESS_NONE:
169 : /* the fallback path always needs to be send uncompressed: we simply
170 : rely on that here */
171 18 : return 0;
172 : case GRPC_COMPRESS_DEFLATE:
173 19 : return zlib_compress(input, output, 0);
174 : case GRPC_COMPRESS_GZIP:
175 776 : return zlib_compress(input, output, 1);
176 : case GRPC_COMPRESS_ALGORITHMS_COUNT:
177 1 : break;
178 : }
179 2 : gpr_log(GPR_ERROR, "invalid compression algorithm %d", algorithm);
180 2 : return 0;
181 : }
182 :
183 815 : int grpc_msg_compress(grpc_compression_algorithm algorithm,
184 : gpr_slice_buffer* input, gpr_slice_buffer* output) {
185 815 : if (!compress_inner(algorithm, input, output)) {
186 719 : copy(input, output);
187 719 : return 0;
188 : }
189 96 : return 1;
190 : }
191 :
192 126 : int grpc_msg_decompress(grpc_compression_algorithm algorithm,
193 : gpr_slice_buffer* input, gpr_slice_buffer* output) {
194 126 : switch (algorithm) {
195 : case GRPC_COMPRESS_NONE:
196 30 : return copy(input, output);
197 : case GRPC_COMPRESS_DEFLATE:
198 14 : return zlib_decompress(input, output, 0);
199 : case GRPC_COMPRESS_GZIP:
200 80 : return zlib_decompress(input, output, 1);
201 : case GRPC_COMPRESS_ALGORITHMS_COUNT:
202 1 : break;
203 : }
204 2 : gpr_log(GPR_ERROR, "invalid compression algorithm %d", algorithm);
205 2 : return 0;
206 : }
|