message_compress_test.cc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. /*
  2. *
  3. * Copyright 2015 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. #include "src/core/lib/compression/message_compress.h"
  19. #include <stdlib.h>
  20. #include <string.h>
  21. #include <grpc/grpc.h>
  22. #include <grpc/support/log.h>
  23. #include "src/core/lib/gpr/murmur_hash.h"
  24. #include "src/core/lib/gpr/useful.h"
  25. #include "src/core/lib/iomgr/exec_ctx.h"
  26. #include "test/core/util/slice_splitter.h"
  27. #include "test/core/util/test_config.h"
  28. typedef enum { ONE_A = 0, ONE_KB_A, ONE_MB_A, TEST_VALUE_COUNT } test_value;
  29. typedef enum {
  30. SHOULD_NOT_COMPRESS,
  31. SHOULD_COMPRESS,
  32. MAYBE_COMPRESSES
  33. } compressability;
  34. static void assert_passthrough(grpc_slice value,
  35. grpc_compression_algorithm algorithm,
  36. grpc_slice_split_mode uncompressed_split_mode,
  37. grpc_slice_split_mode compressed_split_mode,
  38. compressability compress_result_check) {
  39. grpc_slice_buffer input;
  40. grpc_slice_buffer compressed_raw;
  41. grpc_slice_buffer compressed;
  42. grpc_slice_buffer output;
  43. grpc_slice final;
  44. int was_compressed;
  45. const char* algorithm_name;
  46. GPR_ASSERT(grpc_compression_algorithm_name(algorithm, &algorithm_name) != 0);
  47. gpr_log(GPR_INFO,
  48. "assert_passthrough: value_length=%" PRIuPTR
  49. " value_hash=0x%08x "
  50. "algorithm='%s' uncompressed_split='%s' compressed_split='%s'",
  51. GRPC_SLICE_LENGTH(value),
  52. gpr_murmur_hash3(GRPC_SLICE_START_PTR(value),
  53. GRPC_SLICE_LENGTH(value), 0),
  54. algorithm_name, grpc_slice_split_mode_name(uncompressed_split_mode),
  55. grpc_slice_split_mode_name(compressed_split_mode));
  56. grpc_slice_buffer_init(&input);
  57. grpc_slice_buffer_init(&compressed_raw);
  58. grpc_slice_buffer_init(&compressed);
  59. grpc_slice_buffer_init(&output);
  60. grpc_split_slices_to_buffer(uncompressed_split_mode, &value, 1, &input);
  61. {
  62. grpc_core::ExecCtx exec_ctx;
  63. was_compressed = grpc_msg_compress(algorithm, &input, &compressed_raw);
  64. }
  65. GPR_ASSERT(input.count > 0);
  66. switch (compress_result_check) {
  67. case SHOULD_NOT_COMPRESS:
  68. GPR_ASSERT(was_compressed == 0);
  69. break;
  70. case SHOULD_COMPRESS:
  71. GPR_ASSERT(was_compressed == 1);
  72. break;
  73. case MAYBE_COMPRESSES:
  74. /* no check */
  75. break;
  76. }
  77. grpc_split_slice_buffer(compressed_split_mode, &compressed_raw, &compressed);
  78. {
  79. grpc_core::ExecCtx exec_ctx;
  80. GPR_ASSERT(grpc_msg_decompress(
  81. was_compressed ? algorithm : GRPC_COMPRESS_NONE, &compressed, &output));
  82. }
  83. final = grpc_slice_merge(output.slices, output.count);
  84. GPR_ASSERT(grpc_slice_eq(value, final));
  85. grpc_slice_buffer_destroy(&input);
  86. grpc_slice_buffer_destroy(&compressed);
  87. grpc_slice_buffer_destroy(&compressed_raw);
  88. grpc_slice_buffer_destroy(&output);
  89. grpc_slice_unref(final);
  90. }
  91. static grpc_slice repeated(char c, size_t length) {
  92. grpc_slice out = grpc_slice_malloc(length);
  93. memset(GRPC_SLICE_START_PTR(out), c, length);
  94. return out;
  95. }
  96. static compressability get_compressability(
  97. test_value id, grpc_compression_algorithm algorithm) {
  98. if (algorithm == GRPC_COMPRESS_NONE) return SHOULD_NOT_COMPRESS;
  99. switch (id) {
  100. case ONE_A:
  101. return SHOULD_NOT_COMPRESS;
  102. case ONE_KB_A:
  103. case ONE_MB_A:
  104. return SHOULD_COMPRESS;
  105. case TEST_VALUE_COUNT:
  106. abort();
  107. }
  108. return MAYBE_COMPRESSES;
  109. }
  110. static grpc_slice create_test_value(test_value id) {
  111. switch (id) {
  112. case ONE_A:
  113. return grpc_slice_from_copied_string("a");
  114. case ONE_KB_A:
  115. return repeated('a', 1024);
  116. case ONE_MB_A:
  117. return repeated('a', 1024 * 1024);
  118. case TEST_VALUE_COUNT:
  119. abort();
  120. }
  121. return grpc_slice_from_copied_string("bad value");
  122. }
  123. static void test_tiny_data_compress(void) {
  124. grpc_slice_buffer input;
  125. grpc_slice_buffer output;
  126. grpc_slice_buffer_init(&input);
  127. grpc_slice_buffer_init(&output);
  128. grpc_slice_buffer_add(&input, create_test_value(ONE_A));
  129. for (int i = 0; i < GRPC_COMPRESS_ALGORITHMS_COUNT; i++) {
  130. if (i == GRPC_COMPRESS_NONE) continue;
  131. grpc_core::ExecCtx exec_ctx;
  132. GPR_ASSERT(0 ==
  133. grpc_msg_compress(static_cast<grpc_compression_algorithm>(i),
  134. &input, &output));
  135. GPR_ASSERT(1 == output.count);
  136. }
  137. grpc_slice_buffer_destroy(&input);
  138. grpc_slice_buffer_destroy(&output);
  139. }
  140. static void test_bad_decompression_data_crc(void) {
  141. grpc_slice_buffer input;
  142. grpc_slice_buffer corrupted;
  143. grpc_slice_buffer output;
  144. size_t idx;
  145. const uint32_t bad = 0xdeadbeef;
  146. grpc_slice_buffer_init(&input);
  147. grpc_slice_buffer_init(&corrupted);
  148. grpc_slice_buffer_init(&output);
  149. grpc_slice_buffer_add(&input, create_test_value(ONE_MB_A));
  150. grpc_core::ExecCtx exec_ctx;
  151. /* compress it */
  152. grpc_msg_compress(GRPC_COMPRESS_GZIP, &input, &corrupted);
  153. /* corrupt the output by smashing the CRC */
  154. GPR_ASSERT(corrupted.count > 1);
  155. GPR_ASSERT(GRPC_SLICE_LENGTH(corrupted.slices[1]) > 8);
  156. idx = GRPC_SLICE_LENGTH(corrupted.slices[1]) - 8;
  157. memcpy(GRPC_SLICE_START_PTR(corrupted.slices[1]) + idx, &bad, 4);
  158. /* try (and fail) to decompress the corrupted compresed buffer */
  159. GPR_ASSERT(0 == grpc_msg_decompress(GRPC_COMPRESS_GZIP, &corrupted, &output));
  160. grpc_slice_buffer_destroy(&input);
  161. grpc_slice_buffer_destroy(&corrupted);
  162. grpc_slice_buffer_destroy(&output);
  163. }
  164. static void test_bad_decompression_data_missing_trailer(void) {
  165. grpc_slice_buffer input;
  166. grpc_slice_buffer decompressed;
  167. grpc_slice_buffer garbage;
  168. grpc_slice_buffer output;
  169. grpc_slice_buffer_init(&input);
  170. grpc_slice_buffer_init(&decompressed);
  171. grpc_slice_buffer_init(&garbage);
  172. grpc_slice_buffer_init(&output);
  173. grpc_slice_buffer_add(&input, create_test_value(ONE_MB_A));
  174. grpc_core::ExecCtx exec_ctx;
  175. /* compress it */
  176. grpc_msg_compress(GRPC_COMPRESS_GZIP, &input, &decompressed);
  177. GPR_ASSERT(decompressed.length > 8);
  178. /* Remove the footer from the decompressed message */
  179. grpc_slice_buffer_trim_end(&decompressed, 8, &garbage);
  180. /* try (and fail) to decompress the compressed buffer without the footer */
  181. GPR_ASSERT(0 ==
  182. grpc_msg_decompress(GRPC_COMPRESS_GZIP, &decompressed, &output));
  183. grpc_slice_buffer_destroy(&input);
  184. grpc_slice_buffer_destroy(&decompressed);
  185. grpc_slice_buffer_destroy(&garbage);
  186. grpc_slice_buffer_destroy(&output);
  187. }
  188. static void test_bad_decompression_data_trailing_garbage(void) {
  189. grpc_slice_buffer input;
  190. grpc_slice_buffer output;
  191. grpc_slice_buffer_init(&input);
  192. grpc_slice_buffer_init(&output);
  193. /* append 0x99 to the end of an otherwise valid stream */
  194. grpc_slice_buffer_add(
  195. &input, grpc_slice_from_copied_buffer(
  196. "\x78\xda\x63\x60\x60\x60\x00\x00\x00\x04\x00\x01\x99", 13));
  197. /* try (and fail) to decompress the invalid compresed buffer */
  198. grpc_core::ExecCtx exec_ctx;
  199. GPR_ASSERT(0 == grpc_msg_decompress(GRPC_COMPRESS_DEFLATE, &input, &output));
  200. grpc_slice_buffer_destroy(&input);
  201. grpc_slice_buffer_destroy(&output);
  202. }
  203. static void test_bad_decompression_data_stream(void) {
  204. grpc_slice_buffer input;
  205. grpc_slice_buffer output;
  206. grpc_slice_buffer_init(&input);
  207. grpc_slice_buffer_init(&output);
  208. grpc_slice_buffer_add(&input,
  209. grpc_slice_from_copied_buffer("\x78\xda\xff\xff", 4));
  210. /* try (and fail) to decompress the invalid compresed buffer */
  211. grpc_core::ExecCtx exec_ctx;
  212. GPR_ASSERT(0 == grpc_msg_decompress(GRPC_COMPRESS_DEFLATE, &input, &output));
  213. grpc_slice_buffer_destroy(&input);
  214. grpc_slice_buffer_destroy(&output);
  215. }
  216. static void test_bad_compression_algorithm(void) {
  217. grpc_slice_buffer input;
  218. grpc_slice_buffer output;
  219. int was_compressed;
  220. grpc_slice_buffer_init(&input);
  221. grpc_slice_buffer_init(&output);
  222. grpc_slice_buffer_add(
  223. &input, grpc_slice_from_copied_string("Never gonna give you up"));
  224. grpc_core::ExecCtx exec_ctx;
  225. was_compressed =
  226. grpc_msg_compress(GRPC_COMPRESS_ALGORITHMS_COUNT, &input, &output);
  227. GPR_ASSERT(0 == was_compressed);
  228. was_compressed = grpc_msg_compress(static_cast<grpc_compression_algorithm>(
  229. GRPC_COMPRESS_ALGORITHMS_COUNT + 123),
  230. &input, &output);
  231. GPR_ASSERT(0 == was_compressed);
  232. grpc_slice_buffer_destroy(&input);
  233. grpc_slice_buffer_destroy(&output);
  234. }
  235. static void test_bad_decompression_algorithm(void) {
  236. grpc_slice_buffer input;
  237. grpc_slice_buffer output;
  238. int was_decompressed;
  239. grpc_slice_buffer_init(&input);
  240. grpc_slice_buffer_init(&output);
  241. grpc_slice_buffer_add(&input,
  242. grpc_slice_from_copied_string(
  243. "I'm not really compressed but it doesn't matter"));
  244. grpc_core::ExecCtx exec_ctx;
  245. was_decompressed =
  246. grpc_msg_decompress(GRPC_COMPRESS_ALGORITHMS_COUNT, &input, &output);
  247. GPR_ASSERT(0 == was_decompressed);
  248. was_decompressed =
  249. grpc_msg_decompress(static_cast<grpc_compression_algorithm>(
  250. GRPC_COMPRESS_ALGORITHMS_COUNT + 123),
  251. &input, &output);
  252. GPR_ASSERT(0 == was_decompressed);
  253. grpc_slice_buffer_destroy(&input);
  254. grpc_slice_buffer_destroy(&output);
  255. }
  256. int main(int argc, char** argv) {
  257. unsigned i, j, k, m;
  258. grpc_slice_split_mode uncompressed_split_modes[] = {
  259. GRPC_SLICE_SPLIT_IDENTITY, GRPC_SLICE_SPLIT_ONE_BYTE};
  260. grpc_slice_split_mode compressed_split_modes[] = {GRPC_SLICE_SPLIT_MERGE_ALL,
  261. GRPC_SLICE_SPLIT_IDENTITY,
  262. GRPC_SLICE_SPLIT_ONE_BYTE};
  263. grpc::testing::TestEnvironment env(argc, argv);
  264. grpc_init();
  265. for (i = 0; i < GRPC_COMPRESS_ALGORITHMS_COUNT; i++) {
  266. for (j = 0; j < GPR_ARRAY_SIZE(uncompressed_split_modes); j++) {
  267. for (k = 0; k < GPR_ARRAY_SIZE(compressed_split_modes); k++) {
  268. for (m = 0; m < TEST_VALUE_COUNT; m++) {
  269. grpc_slice slice = create_test_value(static_cast<test_value>(m));
  270. assert_passthrough(
  271. slice, static_cast<grpc_compression_algorithm>(i),
  272. static_cast<grpc_slice_split_mode>(j),
  273. static_cast<grpc_slice_split_mode>(k),
  274. get_compressability(static_cast<test_value>(m),
  275. static_cast<grpc_compression_algorithm>(i)));
  276. grpc_slice_unref(slice);
  277. }
  278. }
  279. }
  280. }
  281. test_tiny_data_compress();
  282. test_bad_decompression_data_crc();
  283. test_bad_decompression_data_missing_trailer();
  284. test_bad_decompression_data_stream();
  285. test_bad_decompression_data_trailing_garbage();
  286. test_bad_compression_algorithm();
  287. test_bad_decompression_algorithm();
  288. grpc_shutdown();
  289. return 0;
  290. }