LCOV - code coverage report
Current view: top level - src/core/compression - message_compress.c (source / functions) Hit Total Coverage
Test: tmp.zDYK9MVh93 Lines: 76 89 85.4 %
Date: 2015-10-10 Functions: 7 7 100.0 %

          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             : }

Generated by: LCOV version 1.10