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 877 : 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 877 : gpr_slice outbuf = gpr_slice_malloc(OUTPUT_BLOCK_SIZE);
52 877 : const uInt uint_max = ~(uInt)0;
53 :
54 877 : GPR_ASSERT(GPR_SLICE_LENGTH(outbuf) <= uint_max);
55 877 : zs->avail_out = (uInt)GPR_SLICE_LENGTH(outbuf);
56 877 : zs->next_out = GPR_SLICE_START_PTR(outbuf);
57 877 : flush = Z_NO_FLUSH;
58 6030 : for (i = 0; i < input->count; i++) {
59 5155 : if (i == input->count - 1) flush = Z_FINISH;
60 5155 : GPR_ASSERT(GPR_SLICE_LENGTH(input->slices[i]) <= uint_max);
61 5155 : zs->avail_in = (uInt)GPR_SLICE_LENGTH(input->slices[i]);
62 5155 : zs->next_in = GPR_SLICE_START_PTR(input->slices[i]);
63 : do {
64 17471 : 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 17471 : r = flate(zs, flush);
72 17471 : if (r == Z_STREAM_ERROR) {
73 0 : gpr_log(GPR_INFO, "zlib: stream error");
74 0 : goto error;
75 : }
76 17471 : } while (zs->avail_out == 0);
77 5155 : if (zs->avail_in) {
78 2 : gpr_log(GPR_INFO, "zlib: not all input consumed");
79 2 : goto error;
80 : }
81 : }
82 :
83 875 : GPR_ASSERT(outbuf.refcount);
84 875 : outbuf.data.refcounted.length -= zs->avail_out;
85 875 : gpr_slice_buffer_add_indexed(output, outbuf);
86 :
87 875 : return 1;
88 :
89 : error:
90 2 : gpr_slice_unref(outbuf);
91 2 : return 0;
92 : }
93 :
94 789 : static int zlib_compress(gpr_slice_buffer* input, gpr_slice_buffer* output,
95 : int gzip) {
96 : z_stream zs;
97 : int r;
98 : size_t i;
99 789 : size_t count_before = output->count;
100 789 : size_t length_before = output->length;
101 789 : memset(&zs, 0, sizeof(zs));
102 789 : r = deflateInit2(&zs, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 15 | (gzip ? 16 : 0),
103 : 8, Z_DEFAULT_STRATEGY);
104 789 : if (r != Z_OK) {
105 0 : gpr_log(GPR_ERROR, "deflateInit2 returns %d", r);
106 0 : return 0;
107 : }
108 789 : r = zlib_body(&zs, input, output, deflate) && output->length < input->length;
109 789 : if (!r) {
110 1398 : for (i = count_before; i < output->count; i++) {
111 699 : gpr_slice_unref(output->slices[i]);
112 : }
113 699 : output->count = count_before;
114 699 : output->length = length_before;
115 : }
116 789 : deflateEnd(&zs);
117 788 : return r;
118 : }
119 :
120 88 : static int zlib_decompress(gpr_slice_buffer* input, gpr_slice_buffer* output,
121 : int gzip) {
122 : z_stream zs;
123 : int r;
124 : size_t i;
125 88 : size_t count_before = output->count;
126 88 : size_t length_before = output->length;
127 88 : memset(&zs, 0, sizeof(zs));
128 88 : r = inflateInit2(&zs, 15 | (gzip ? 16 : 0));
129 88 : if (r != Z_OK) {
130 0 : gpr_log(GPR_ERROR, "inflateInit2 returns %d", r);
131 0 : return 0;
132 : }
133 88 : r = zlib_body(&zs, input, output, inflate);
134 88 : if (!r) {
135 2 : for (i = count_before; i < output->count; i++) {
136 0 : gpr_slice_unref(output->slices[i]);
137 : }
138 2 : output->count = count_before;
139 2 : output->length = length_before;
140 : }
141 88 : inflateEnd(&zs);
142 88 : return r;
143 : }
144 :
145 747 : static int copy(gpr_slice_buffer* input, gpr_slice_buffer* output) {
146 : size_t i;
147 2100690 : for (i = 0; i < input->count; i++) {
148 2099943 : gpr_slice_buffer_add(output, gpr_slice_ref(input->slices[i]));
149 : }
150 747 : return 1;
151 : }
152 :
153 807 : int compress_inner(grpc_compression_algorithm algorithm,
154 : gpr_slice_buffer* input, gpr_slice_buffer* output) {
155 807 : switch (algorithm) {
156 : case GRPC_COMPRESS_NONE:
157 : /* the fallback path always needs to be send uncompressed: we simply
158 : rely on that here */
159 18 : return 0;
160 : case GRPC_COMPRESS_DEFLATE:
161 19 : return zlib_compress(input, output, 0);
162 : case GRPC_COMPRESS_GZIP:
163 770 : return zlib_compress(input, output, 1);
164 : case GRPC_COMPRESS_ALGORITHMS_COUNT:
165 0 : break;
166 : }
167 0 : gpr_log(GPR_ERROR, "invalid compression algorithm %d", algorithm);
168 0 : return 0;
169 : }
170 :
171 807 : int grpc_msg_compress(grpc_compression_algorithm algorithm,
172 : gpr_slice_buffer* input, gpr_slice_buffer* output) {
173 807 : if (!compress_inner(algorithm, input, output)) {
174 717 : copy(input, output);
175 717 : return 0;
176 : }
177 90 : return 1;
178 : }
179 :
180 118 : int grpc_msg_decompress(grpc_compression_algorithm algorithm,
181 : gpr_slice_buffer* input, gpr_slice_buffer* output) {
182 118 : switch (algorithm) {
183 : case GRPC_COMPRESS_NONE:
184 30 : return copy(input, output);
185 : case GRPC_COMPRESS_DEFLATE:
186 14 : return zlib_decompress(input, output, 0);
187 : case GRPC_COMPRESS_GZIP:
188 74 : return zlib_decompress(input, output, 1);
189 : case GRPC_COMPRESS_ALGORITHMS_COUNT:
190 0 : break;
191 : }
192 0 : gpr_log(GPR_ERROR, "invalid compression algorithm %d", algorithm);
193 0 : return 0;
194 : }
|