1 /*
2 *
3 * Copyright 2017 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 <string.h>
20
21 #include <grpc/grpc.h>
22 #include <grpc/slice_buffer.h>
23 #include <grpc/support/alloc.h>
24 #include <grpc/support/log.h>
25
26 #include "src/core/lib/compression/stream_compression.h"
27
generate_random_payload(char * payload,size_t size)28 static void generate_random_payload(char* payload, size_t size) {
29 size_t i;
30 static const char chars[] = "abcdefghijklmnopqrstuvwxyz1234567890";
31 for (i = 0; i < size - 1; ++i) {
32 payload[i] = chars[rand() % static_cast<int>(sizeof(chars) - 1)];
33 }
34 payload[size - 1] = '\0';
35 }
36
slice_buffer_equals_string(grpc_slice_buffer * buf,const char * str)37 static bool slice_buffer_equals_string(grpc_slice_buffer* buf,
38 const char* str) {
39 size_t i;
40 if (buf->length != strlen(str)) {
41 return false;
42 }
43 size_t pointer = 0;
44 for (i = 0; i < buf->count; i++) {
45 size_t slice_len = GRPC_SLICE_LENGTH(buf->slices[i]);
46 if (0 !=
47 strncmp(str + pointer,
48 reinterpret_cast<char*> GRPC_SLICE_START_PTR(buf->slices[i]),
49 slice_len)) {
50 return false;
51 }
52 pointer += slice_len;
53 }
54 return true;
55 }
56
test_stream_compression_simple_compress_decompress()57 static void test_stream_compression_simple_compress_decompress() {
58 const char test_str[] = "aaaaaaabbbbbbbccccccctesttesttest";
59 grpc_slice_buffer source, relay, sink;
60 grpc_slice_buffer_init(&source);
61 grpc_slice_buffer_init(&relay);
62 grpc_slice_buffer_init(&sink);
63 grpc_stream_compression_context* compress_ctx =
64 grpc_stream_compression_context_create(
65 GRPC_STREAM_COMPRESSION_GZIP_COMPRESS);
66 grpc_stream_compression_context* decompress_ctx =
67 grpc_stream_compression_context_create(
68 GRPC_STREAM_COMPRESSION_GZIP_DECOMPRESS);
69 grpc_slice slice = grpc_slice_from_static_string(test_str);
70 grpc_slice_buffer_add(&source, slice);
71 GPR_ASSERT(grpc_stream_compress(compress_ctx, &source, &relay, nullptr,
72 ~(size_t)0,
73 GRPC_STREAM_COMPRESSION_FLUSH_FINISH));
74 bool end_of_context;
75 size_t output_size;
76 GPR_ASSERT(grpc_stream_decompress(decompress_ctx, &relay, &sink, &output_size,
77 ~(size_t)0, &end_of_context));
78 GPR_ASSERT(output_size == sizeof(test_str) - 1);
79 grpc_stream_compression_context_destroy(compress_ctx);
80 grpc_stream_compression_context_destroy(decompress_ctx);
81
82 GPR_ASSERT(slice_buffer_equals_string(&sink, test_str));
83
84 grpc_slice_buffer_destroy(&source);
85 grpc_slice_buffer_destroy(&relay);
86 grpc_slice_buffer_destroy(&sink);
87 }
88
89 static void
test_stream_compression_simple_compress_decompress_with_output_size_constraint()90 test_stream_compression_simple_compress_decompress_with_output_size_constraint() {
91 const char test_str[] = "aaaaaaabbbbbbbccccccctesttesttest";
92 grpc_slice_buffer source, relay, sink;
93 grpc_slice_buffer_init(&source);
94 grpc_slice_buffer_init(&relay);
95 grpc_slice_buffer_init(&sink);
96 grpc_stream_compression_context* compress_ctx =
97 grpc_stream_compression_context_create(
98 GRPC_STREAM_COMPRESSION_GZIP_COMPRESS);
99 grpc_stream_compression_context* decompress_ctx =
100 grpc_stream_compression_context_create(
101 GRPC_STREAM_COMPRESSION_GZIP_DECOMPRESS);
102 grpc_slice slice = grpc_slice_from_static_string(test_str);
103 grpc_slice_buffer_add(&source, slice);
104 GPR_ASSERT(grpc_stream_compress(compress_ctx, &source, &relay, nullptr,
105 ~(size_t)0,
106 GRPC_STREAM_COMPRESSION_FLUSH_FINISH));
107 grpc_stream_compression_context_destroy(compress_ctx);
108
109 bool end_of_context;
110 size_t output_size;
111 size_t max_output_size = 2;
112 GPR_ASSERT(grpc_stream_decompress(decompress_ctx, &relay, &sink, &output_size,
113 max_output_size, &end_of_context));
114 GPR_ASSERT(output_size == max_output_size);
115 GPR_ASSERT(end_of_context == false);
116 grpc_slice slice_recv = grpc_slice_buffer_take_first(&sink);
117 char* str_recv = reinterpret_cast<char*> GRPC_SLICE_START_PTR(slice_recv);
118 GPR_ASSERT(GRPC_SLICE_LENGTH(slice_recv) == max_output_size);
119 GPR_ASSERT(0 == strncmp(test_str, str_recv, max_output_size));
120 grpc_slice_unref(slice_recv);
121
122 size_t remaining_size = sizeof(test_str) - 1 - max_output_size;
123 GPR_ASSERT(grpc_stream_decompress(decompress_ctx, &relay, &sink, &output_size,
124 remaining_size, &end_of_context));
125 GPR_ASSERT(output_size == remaining_size);
126 GPR_ASSERT(end_of_context == true);
127
128 GPR_ASSERT(slice_buffer_equals_string(&sink, test_str + max_output_size));
129
130 grpc_stream_compression_context_destroy(decompress_ctx);
131 grpc_slice_buffer_destroy(&source);
132 grpc_slice_buffer_destroy(&relay);
133 grpc_slice_buffer_destroy(&sink);
134 }
135
136 #define LARGE_DATA_SIZE (1024 * 1024)
137 static void
test_stream_compression_simple_compress_decompress_with_large_data()138 test_stream_compression_simple_compress_decompress_with_large_data() {
139 char* test_str =
140 static_cast<char*>(gpr_malloc(LARGE_DATA_SIZE * sizeof(char)));
141 generate_random_payload(test_str, LARGE_DATA_SIZE);
142 grpc_slice_buffer source, relay, sink;
143 grpc_slice_buffer_init(&source);
144 grpc_slice_buffer_init(&relay);
145 grpc_slice_buffer_init(&sink);
146 grpc_stream_compression_context* compress_ctx =
147 grpc_stream_compression_context_create(
148 GRPC_STREAM_COMPRESSION_GZIP_COMPRESS);
149 grpc_stream_compression_context* decompress_ctx =
150 grpc_stream_compression_context_create(
151 GRPC_STREAM_COMPRESSION_GZIP_DECOMPRESS);
152 grpc_slice slice = grpc_slice_from_static_string(test_str);
153 grpc_slice_buffer_add(&source, slice);
154 GPR_ASSERT(grpc_stream_compress(compress_ctx, &source, &relay, nullptr,
155 ~(size_t)0,
156 GRPC_STREAM_COMPRESSION_FLUSH_FINISH));
157 bool end_of_context;
158 size_t output_size;
159 GPR_ASSERT(grpc_stream_decompress(decompress_ctx, &relay, &sink, &output_size,
160 ~(size_t)0, &end_of_context));
161 GPR_ASSERT(output_size == LARGE_DATA_SIZE - 1);
162 grpc_stream_compression_context_destroy(compress_ctx);
163 grpc_stream_compression_context_destroy(decompress_ctx);
164
165 GPR_ASSERT(slice_buffer_equals_string(&sink, test_str));
166
167 grpc_slice_buffer_destroy(&source);
168 grpc_slice_buffer_destroy(&relay);
169 grpc_slice_buffer_destroy(&sink);
170 gpr_free(test_str);
171 }
172
test_stream_compression_drop_context()173 static void test_stream_compression_drop_context() {
174 const char test_str[] = "aaaaaaabbbbbbbccccccc";
175 const char test_str2[] = "dddddddeeeeeeefffffffggggg";
176 grpc_slice_buffer source, relay, sink;
177 grpc_slice_buffer_init(&source);
178 grpc_slice_buffer_init(&relay);
179 grpc_slice_buffer_init(&sink);
180 grpc_stream_compression_context* compress_ctx =
181 grpc_stream_compression_context_create(
182 GRPC_STREAM_COMPRESSION_GZIP_COMPRESS);
183 grpc_slice slice = grpc_slice_from_static_string(test_str);
184 grpc_slice_buffer_add(&source, slice);
185 GPR_ASSERT(grpc_stream_compress(compress_ctx, &source, &relay, nullptr,
186 ~(size_t)0,
187 GRPC_STREAM_COMPRESSION_FLUSH_FINISH));
188 grpc_stream_compression_context_destroy(compress_ctx);
189
190 compress_ctx = grpc_stream_compression_context_create(
191 GRPC_STREAM_COMPRESSION_GZIP_COMPRESS);
192 slice = grpc_slice_from_static_string(test_str2);
193 grpc_slice_buffer_add(&source, slice);
194 GPR_ASSERT(grpc_stream_compress(compress_ctx, &source, &relay, nullptr,
195 ~(size_t)0,
196 GRPC_STREAM_COMPRESSION_FLUSH_FINISH));
197 grpc_stream_compression_context_destroy(compress_ctx);
198
199 /* Concatenate the two compressed sliced into one to test decompressing two
200 * contexts */
201 grpc_slice slice1 = grpc_slice_buffer_take_first(&relay);
202 grpc_slice slice2 = grpc_slice_buffer_take_first(&relay);
203 grpc_slice slice3 =
204 grpc_slice_malloc(GRPC_SLICE_LENGTH(slice1) + GRPC_SLICE_LENGTH(slice2));
205 memcpy(GRPC_SLICE_START_PTR(slice3), GRPC_SLICE_START_PTR(slice1),
206 GRPC_SLICE_LENGTH(slice1));
207 memcpy(GRPC_SLICE_START_PTR(slice3) + GRPC_SLICE_LENGTH(slice1),
208 GRPC_SLICE_START_PTR(slice2), GRPC_SLICE_LENGTH(slice2));
209 grpc_slice_unref(slice1);
210 grpc_slice_unref(slice2);
211 grpc_slice_buffer_add(&relay, slice3);
212
213 grpc_stream_compression_context* decompress_ctx =
214 grpc_stream_compression_context_create(
215 GRPC_STREAM_COMPRESSION_GZIP_DECOMPRESS);
216 bool end_of_context;
217 size_t output_size;
218 GPR_ASSERT(grpc_stream_decompress(decompress_ctx, &relay, &sink, &output_size,
219 ~(size_t)0, &end_of_context));
220 GPR_ASSERT(end_of_context == true);
221 GPR_ASSERT(output_size == sizeof(test_str) - 1);
222
223 GPR_ASSERT(slice_buffer_equals_string(&sink, test_str));
224 grpc_stream_compression_context_destroy(decompress_ctx);
225 grpc_slice_buffer_destroy(&sink);
226
227 grpc_slice_buffer_init(&sink);
228 decompress_ctx = grpc_stream_compression_context_create(
229 GRPC_STREAM_COMPRESSION_GZIP_DECOMPRESS);
230 GPR_ASSERT(grpc_stream_decompress(decompress_ctx, &relay, &sink, &output_size,
231 ~(size_t)0, &end_of_context));
232 GPR_ASSERT(end_of_context == true);
233 GPR_ASSERT(output_size == sizeof(test_str2) - 1);
234 GPR_ASSERT(slice_buffer_equals_string(&sink, test_str2));
235 grpc_stream_compression_context_destroy(decompress_ctx);
236
237 grpc_slice_buffer_destroy(&source);
238 grpc_slice_buffer_destroy(&relay);
239 grpc_slice_buffer_destroy(&sink);
240 }
241
test_stream_compression_sync_flush()242 static void test_stream_compression_sync_flush() {
243 const char test_str[] = "aaaaaaabbbbbbbccccccc";
244 const char test_str2[] = "dddddddeeeeeeefffffffggggg";
245 grpc_slice_buffer source, relay, sink;
246 grpc_slice_buffer_init(&source);
247 grpc_slice_buffer_init(&relay);
248 grpc_slice_buffer_init(&sink);
249 grpc_stream_compression_context* compress_ctx =
250 grpc_stream_compression_context_create(
251 GRPC_STREAM_COMPRESSION_GZIP_COMPRESS);
252 grpc_slice slice = grpc_slice_from_static_string(test_str);
253 grpc_slice_buffer_add(&source, slice);
254 GPR_ASSERT(grpc_stream_compress(compress_ctx, &source, &relay, nullptr,
255 ~(size_t)0,
256 GRPC_STREAM_COMPRESSION_FLUSH_SYNC));
257
258 grpc_stream_compression_context* decompress_ctx =
259 grpc_stream_compression_context_create(
260 GRPC_STREAM_COMPRESSION_GZIP_DECOMPRESS);
261 bool end_of_context;
262 size_t output_size;
263 GPR_ASSERT(grpc_stream_decompress(decompress_ctx, &relay, &sink, &output_size,
264 ~(size_t)0, &end_of_context));
265 GPR_ASSERT(end_of_context == false);
266 GPR_ASSERT(output_size == sizeof(test_str) - 1);
267 GPR_ASSERT(slice_buffer_equals_string(&sink, test_str));
268 grpc_slice_buffer_destroy(&sink);
269
270 grpc_slice_buffer_init(&sink);
271 slice = grpc_slice_from_static_string(test_str2);
272 grpc_slice_buffer_add(&source, slice);
273 GPR_ASSERT(grpc_stream_compress(compress_ctx, &source, &relay, nullptr,
274 ~(size_t)0,
275 GRPC_STREAM_COMPRESSION_FLUSH_FINISH));
276 grpc_stream_compression_context_destroy(compress_ctx);
277
278 GPR_ASSERT(grpc_stream_decompress(decompress_ctx, &relay, &sink, &output_size,
279 ~(size_t)0, &end_of_context));
280 GPR_ASSERT(end_of_context == true);
281 GPR_ASSERT(output_size == sizeof(test_str2) - 1);
282 GPR_ASSERT(slice_buffer_equals_string(&sink, test_str2));
283 grpc_stream_compression_context_destroy(decompress_ctx);
284
285 grpc_slice_buffer_destroy(&source);
286 grpc_slice_buffer_destroy(&relay);
287 grpc_slice_buffer_destroy(&sink);
288 }
289
main(int argc,char ** argv)290 int main(int argc, char** argv) {
291 grpc_init();
292 test_stream_compression_simple_compress_decompress();
293 test_stream_compression_simple_compress_decompress_with_output_size_constraint();
294 test_stream_compression_simple_compress_decompress_with_large_data();
295 test_stream_compression_sync_flush();
296 test_stream_compression_drop_context();
297 grpc_shutdown();
298
299 return 0;
300 }
301