• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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