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