diff --git a/BUILD b/BUILD
index 6f92ef3858f..9f1ab2a5384 100644
--- a/BUILD
+++ b/BUILD
@@ -571,6 +571,7 @@ grpc_cc_library(
"src/core/lib/channel/handshaker_registry.c",
"src/core/lib/compression/compression.c",
"src/core/lib/compression/message_compress.c",
+ "src/core/lib/compression/stream_compression.c",
"src/core/lib/http/format_request.c",
"src/core/lib/http/httpcli.c",
"src/core/lib/http/parser.c",
@@ -697,6 +698,7 @@ grpc_cc_library(
"src/core/lib/channel/handshaker_registry.h",
"src/core/lib/compression/algorithm_metadata.h",
"src/core/lib/compression/message_compress.h",
+ "src/core/lib/compression/stream_compression.h",
"src/core/lib/http/format_request.h",
"src/core/lib/http/httpcli.h",
"src/core/lib/http/parser.h",
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 6ee9490c250..5413bbcc0f3 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -528,6 +528,7 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
add_dependencies(buildtests_c socket_utils_test)
endif()
add_dependencies(buildtests_c status_conversion_test)
+add_dependencies(buildtests_c stream_compression_test)
add_dependencies(buildtests_c stream_owned_slice_test)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
add_dependencies(buildtests_c tcp_client_posix_test)
@@ -954,6 +955,7 @@ add_library(grpc
src/core/lib/channel/handshaker_registry.c
src/core/lib/compression/compression.c
src/core/lib/compression/message_compress.c
+ src/core/lib/compression/stream_compression.c
src/core/lib/http/format_request.c
src/core/lib/http/httpcli.c
src/core/lib/http/parser.c
@@ -1295,6 +1297,7 @@ add_library(grpc_cronet
src/core/lib/channel/handshaker_registry.c
src/core/lib/compression/compression.c
src/core/lib/compression/message_compress.c
+ src/core/lib/compression/stream_compression.c
src/core/lib/http/format_request.c
src/core/lib/http/httpcli.c
src/core/lib/http/parser.c
@@ -1614,6 +1617,7 @@ add_library(grpc_test_util
src/core/lib/channel/handshaker_registry.c
src/core/lib/compression/compression.c
src/core/lib/compression/message_compress.c
+ src/core/lib/compression/stream_compression.c
src/core/lib/http/format_request.c
src/core/lib/http/httpcli.c
src/core/lib/http/parser.c
@@ -1876,6 +1880,7 @@ add_library(grpc_unsecure
src/core/lib/channel/handshaker_registry.c
src/core/lib/compression/compression.c
src/core/lib/compression/message_compress.c
+ src/core/lib/compression/stream_compression.c
src/core/lib/http/format_request.c
src/core/lib/http/httpcli.c
src/core/lib/http/parser.c
@@ -2534,6 +2539,7 @@ add_library(grpc++_cronet
src/core/lib/channel/handshaker_registry.c
src/core/lib/compression/compression.c
src/core/lib/compression/message_compress.c
+ src/core/lib/compression/stream_compression.c
src/core/lib/http/format_request.c
src/core/lib/http/httpcli.c
src/core/lib/http/parser.c
@@ -8181,6 +8187,37 @@ target_link_libraries(status_conversion_test
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
+add_executable(stream_compression_test
+ test/core/compression/stream_compression_test.c
+)
+
+
+target_include_directories(stream_compression_test
+ PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
+ PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
+ PRIVATE ${BORINGSSL_ROOT_DIR}/include
+ PRIVATE ${PROTOBUF_ROOT_DIR}/src
+ PRIVATE ${BENCHMARK_ROOT_DIR}/include
+ PRIVATE ${ZLIB_ROOT_DIR}
+ PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/zlib
+ PRIVATE ${CARES_BUILD_INCLUDE_DIR}
+ PRIVATE ${CARES_INCLUDE_DIR}
+ PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
+ PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
+ PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
+)
+
+target_link_libraries(stream_compression_test
+ ${_gRPC_ALLTARGETS_LIBRARIES}
+ grpc_test_util
+ grpc
+ gpr_test_util
+ gpr
+)
+
+endif (gRPC_BUILD_TESTS)
+if (gRPC_BUILD_TESTS)
+
add_executable(stream_owned_slice_test
test/core/transport/stream_owned_slice_test.c
)
diff --git a/Makefile b/Makefile
index 72468f8f928..210d6768222 100644
--- a/Makefile
+++ b/Makefile
@@ -1075,6 +1075,7 @@ sockaddr_utils_test: $(BINDIR)/$(CONFIG)/sockaddr_utils_test
socket_utils_test: $(BINDIR)/$(CONFIG)/socket_utils_test
ssl_server_fuzzer: $(BINDIR)/$(CONFIG)/ssl_server_fuzzer
status_conversion_test: $(BINDIR)/$(CONFIG)/status_conversion_test
+stream_compression_test: $(BINDIR)/$(CONFIG)/stream_compression_test
stream_owned_slice_test: $(BINDIR)/$(CONFIG)/stream_owned_slice_test
tcp_client_posix_test: $(BINDIR)/$(CONFIG)/tcp_client_posix_test
tcp_client_uv_test: $(BINDIR)/$(CONFIG)/tcp_client_uv_test
@@ -1445,6 +1446,7 @@ buildtests_c: privatelibs_c \
$(BINDIR)/$(CONFIG)/sockaddr_utils_test \
$(BINDIR)/$(CONFIG)/socket_utils_test \
$(BINDIR)/$(CONFIG)/status_conversion_test \
+ $(BINDIR)/$(CONFIG)/stream_compression_test \
$(BINDIR)/$(CONFIG)/stream_owned_slice_test \
$(BINDIR)/$(CONFIG)/tcp_client_posix_test \
$(BINDIR)/$(CONFIG)/tcp_client_uv_test \
@@ -1929,6 +1931,8 @@ test_c: buildtests_c
$(Q) $(BINDIR)/$(CONFIG)/socket_utils_test || ( echo test socket_utils_test failed ; exit 1 )
$(E) "[RUN] Testing status_conversion_test"
$(Q) $(BINDIR)/$(CONFIG)/status_conversion_test || ( echo test status_conversion_test failed ; exit 1 )
+ $(E) "[RUN] Testing stream_compression_test"
+ $(Q) $(BINDIR)/$(CONFIG)/stream_compression_test || ( echo test stream_compression_test failed ; exit 1 )
$(E) "[RUN] Testing stream_owned_slice_test"
$(Q) $(BINDIR)/$(CONFIG)/stream_owned_slice_test || ( echo test stream_owned_slice_test failed ; exit 1 )
$(E) "[RUN] Testing tcp_client_posix_test"
@@ -2891,6 +2895,7 @@ LIBGRPC_SRC = \
src/core/lib/channel/handshaker_registry.c \
src/core/lib/compression/compression.c \
src/core/lib/compression/message_compress.c \
+ src/core/lib/compression/stream_compression.c \
src/core/lib/http/format_request.c \
src/core/lib/http/httpcli.c \
src/core/lib/http/parser.c \
@@ -3230,6 +3235,7 @@ LIBGRPC_CRONET_SRC = \
src/core/lib/channel/handshaker_registry.c \
src/core/lib/compression/compression.c \
src/core/lib/compression/message_compress.c \
+ src/core/lib/compression/stream_compression.c \
src/core/lib/http/format_request.c \
src/core/lib/http/httpcli.c \
src/core/lib/http/parser.c \
@@ -3546,6 +3552,7 @@ LIBGRPC_TEST_UTIL_SRC = \
src/core/lib/channel/handshaker_registry.c \
src/core/lib/compression/compression.c \
src/core/lib/compression/message_compress.c \
+ src/core/lib/compression/stream_compression.c \
src/core/lib/http/format_request.c \
src/core/lib/http/httpcli.c \
src/core/lib/http/parser.c \
@@ -3780,6 +3787,7 @@ LIBGRPC_UNSECURE_SRC = \
src/core/lib/channel/handshaker_registry.c \
src/core/lib/compression/compression.c \
src/core/lib/compression/message_compress.c \
+ src/core/lib/compression/stream_compression.c \
src/core/lib/http/format_request.c \
src/core/lib/http/httpcli.c \
src/core/lib/http/parser.c \
@@ -4422,6 +4430,7 @@ LIBGRPC++_CRONET_SRC = \
src/core/lib/channel/handshaker_registry.c \
src/core/lib/compression/compression.c \
src/core/lib/compression/message_compress.c \
+ src/core/lib/compression/stream_compression.c \
src/core/lib/http/format_request.c \
src/core/lib/http/httpcli.c \
src/core/lib/http/parser.c \
@@ -12265,6 +12274,38 @@ endif
endif
+STREAM_COMPRESSION_TEST_SRC = \
+ test/core/compression/stream_compression_test.c \
+
+STREAM_COMPRESSION_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(STREAM_COMPRESSION_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/stream_compression_test: openssl_dep_error
+
+else
+
+
+
+$(BINDIR)/$(CONFIG)/stream_compression_test: $(STREAM_COMPRESSION_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+ $(E) "[LD] Linking $@"
+ $(Q) mkdir -p `dirname $@`
+ $(Q) $(LD) $(LDFLAGS) $(STREAM_COMPRESSION_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/stream_compression_test
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/core/compression/stream_compression_test.o: $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+deps_stream_compression_test: $(STREAM_COMPRESSION_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(STREAM_COMPRESSION_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
STREAM_OWNED_SLICE_TEST_SRC = \
test/core/transport/stream_owned_slice_test.c \
diff --git a/binding.gyp b/binding.gyp
index 00fbe70fee8..ae78d931f2d 100644
--- a/binding.gyp
+++ b/binding.gyp
@@ -645,6 +645,7 @@
'src/core/lib/channel/handshaker_registry.c',
'src/core/lib/compression/compression.c',
'src/core/lib/compression/message_compress.c',
+ 'src/core/lib/compression/stream_compression.c',
'src/core/lib/http/format_request.c',
'src/core/lib/http/httpcli.c',
'src/core/lib/http/parser.c',
diff --git a/build.yaml b/build.yaml
index 1b9eb63bcdc..581fa65a235 100644
--- a/build.yaml
+++ b/build.yaml
@@ -191,6 +191,7 @@ filegroups:
- src/core/lib/channel/handshaker_registry.h
- src/core/lib/compression/algorithm_metadata.h
- src/core/lib/compression/message_compress.h
+ - src/core/lib/compression/stream_compression.h
- src/core/lib/http/format_request.h
- src/core/lib/http/httpcli.h
- src/core/lib/http/parser.h
@@ -300,6 +301,7 @@ filegroups:
- src/core/lib/channel/handshaker_registry.c
- src/core/lib/compression/compression.c
- src/core/lib/compression/message_compress.c
+ - src/core/lib/compression/stream_compression.c
- src/core/lib/http/format_request.c
- src/core/lib/http/httpcli.c
- src/core/lib/http/parser.c
@@ -3009,6 +3011,16 @@ targets:
- grpc
- gpr_test_util
- gpr
+- name: stream_compression_test
+ build: test
+ language: c
+ src:
+ - test/core/compression/stream_compression_test.c
+ deps:
+ - grpc_test_util
+ - grpc
+ - gpr_test_util
+ - gpr
- name: stream_owned_slice_test
build: test
language: c
diff --git a/config.m4 b/config.m4
index 71e5776d851..e214f9c5464 100644
--- a/config.m4
+++ b/config.m4
@@ -95,6 +95,7 @@ if test "$PHP_GRPC" != "no"; then
src/core/lib/channel/handshaker_registry.c \
src/core/lib/compression/compression.c \
src/core/lib/compression/message_compress.c \
+ src/core/lib/compression/stream_compression.c \
src/core/lib/http/format_request.c \
src/core/lib/http/httpcli.c \
src/core/lib/http/parser.c \
diff --git a/config.w32 b/config.w32
index cd374bae650..6d50712fb54 100644
--- a/config.w32
+++ b/config.w32
@@ -72,6 +72,7 @@ if (PHP_GRPC != "no") {
"src\\core\\lib\\channel\\handshaker_registry.c " +
"src\\core\\lib\\compression\\compression.c " +
"src\\core\\lib\\compression\\message_compress.c " +
+ "src\\core\\lib\\compression\\stream_compression.c " +
"src\\core\\lib\\http\\format_request.c " +
"src\\core\\lib\\http\\httpcli.c " +
"src\\core\\lib\\http\\parser.c " +
diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec
index fc51a92daf8..cf3fc3598a2 100644
--- a/gRPC-Core.podspec
+++ b/gRPC-Core.podspec
@@ -254,6 +254,7 @@ Pod::Spec.new do |s|
'src/core/lib/channel/handshaker_registry.h',
'src/core/lib/compression/algorithm_metadata.h',
'src/core/lib/compression/message_compress.h',
+ 'src/core/lib/compression/stream_compression.h',
'src/core/lib/http/format_request.h',
'src/core/lib/http/httpcli.h',
'src/core/lib/http/parser.h',
@@ -467,6 +468,7 @@ Pod::Spec.new do |s|
'src/core/lib/channel/handshaker_registry.c',
'src/core/lib/compression/compression.c',
'src/core/lib/compression/message_compress.c',
+ 'src/core/lib/compression/stream_compression.c',
'src/core/lib/http/format_request.c',
'src/core/lib/http/httpcli.c',
'src/core/lib/http/parser.c',
@@ -734,6 +736,7 @@ Pod::Spec.new do |s|
'src/core/lib/channel/handshaker_registry.h',
'src/core/lib/compression/algorithm_metadata.h',
'src/core/lib/compression/message_compress.h',
+ 'src/core/lib/compression/stream_compression.h',
'src/core/lib/http/format_request.h',
'src/core/lib/http/httpcli.h',
'src/core/lib/http/parser.h',
diff --git a/grpc.gemspec b/grpc.gemspec
index ab4a634c9b0..a87c113b04b 100755
--- a/grpc.gemspec
+++ b/grpc.gemspec
@@ -186,6 +186,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/channel/handshaker_registry.h )
s.files += %w( src/core/lib/compression/algorithm_metadata.h )
s.files += %w( src/core/lib/compression/message_compress.h )
+ s.files += %w( src/core/lib/compression/stream_compression.h )
s.files += %w( src/core/lib/http/format_request.h )
s.files += %w( src/core/lib/http/httpcli.h )
s.files += %w( src/core/lib/http/parser.h )
@@ -403,6 +404,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/channel/handshaker_registry.c )
s.files += %w( src/core/lib/compression/compression.c )
s.files += %w( src/core/lib/compression/message_compress.c )
+ s.files += %w( src/core/lib/compression/stream_compression.c )
s.files += %w( src/core/lib/http/format_request.c )
s.files += %w( src/core/lib/http/httpcli.c )
s.files += %w( src/core/lib/http/parser.c )
diff --git a/package.xml b/package.xml
index 602800b1b51..256a21d017b 100644
--- a/package.xml
+++ b/package.xml
@@ -200,6 +200,7 @@
+
@@ -417,6 +418,7 @@
+
diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.c b/src/core/ext/transport/chttp2/transport/chttp2_transport.c
index bd25f69a1de..731ebf400f7 100644
--- a/src/core/ext/transport/chttp2/transport/chttp2_transport.c
+++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.c
@@ -33,6 +33,7 @@
#include "src/core/ext/transport/chttp2/transport/internal.h"
#include "src/core/ext/transport/chttp2/transport/varint.h"
#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/compression/stream_compression.h"
#include "src/core/lib/http/parser.h"
#include "src/core/lib/iomgr/executor.h"
#include "src/core/lib/iomgr/timer.h"
diff --git a/src/core/ext/transport/chttp2/transport/internal.h b/src/core/ext/transport/chttp2/transport/internal.h
index a5b67e5abaa..4563b78e755 100644
--- a/src/core/ext/transport/chttp2/transport/internal.h
+++ b/src/core/ext/transport/chttp2/transport/internal.h
@@ -33,6 +33,7 @@
#include "src/core/ext/transport/chttp2/transport/hpack_parser.h"
#include "src/core/ext/transport/chttp2/transport/incoming_metadata.h"
#include "src/core/ext/transport/chttp2/transport/stream_map.h"
+#include "src/core/lib/compression/stream_compression.h"
#include "src/core/lib/iomgr/combiner.h"
#include "src/core/lib/iomgr/endpoint.h"
#include "src/core/lib/iomgr/timer.h"
diff --git a/src/core/lib/compression/stream_compression.c b/src/core/lib/compression/stream_compression.c
new file mode 100644
index 00000000000..df13d53e06f
--- /dev/null
+++ b/src/core/lib/compression/stream_compression.c
@@ -0,0 +1,191 @@
+/*
+ *
+ * Copyright 2017 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include
+#include
+
+#include "src/core/lib/compression/stream_compression.h"
+#include "src/core/lib/iomgr/exec_ctx.h"
+#include "src/core/lib/slice/slice_internal.h"
+
+#define OUTPUT_BLOCK_SIZE (1024)
+
+static bool gzip_flate(grpc_stream_compression_context *ctx,
+ grpc_slice_buffer *in, grpc_slice_buffer *out,
+ size_t *output_size, size_t max_output_size, int flush,
+ bool *end_of_context) {
+ GPR_ASSERT(flush == 0 || flush == Z_SYNC_FLUSH || flush == Z_FINISH);
+ /* Full flush is not allowed when inflating. */
+ GPR_ASSERT(!(ctx->flate == inflate && (flush == Z_FINISH)));
+
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ int r;
+ bool eoc = false;
+ size_t original_max_output_size = max_output_size;
+ while (max_output_size > 0 && (in->length > 0 || flush) && !eoc) {
+ size_t slice_size = max_output_size < OUTPUT_BLOCK_SIZE ? max_output_size
+ : OUTPUT_BLOCK_SIZE;
+ grpc_slice slice_out = GRPC_SLICE_MALLOC(slice_size);
+ ctx->zs.avail_out = (uInt)slice_size;
+ ctx->zs.next_out = GRPC_SLICE_START_PTR(slice_out);
+ while (ctx->zs.avail_out > 0 && in->length > 0 && !eoc) {
+ grpc_slice slice = grpc_slice_buffer_take_first(in);
+ ctx->zs.avail_in = (uInt)GRPC_SLICE_LENGTH(slice);
+ ctx->zs.next_in = GRPC_SLICE_START_PTR(slice);
+ r = ctx->flate(&ctx->zs, Z_NO_FLUSH);
+ if (r < 0 && r != Z_BUF_ERROR) {
+ gpr_log(GPR_ERROR, "zlib error (%d)", r);
+ grpc_slice_unref_internal(&exec_ctx, slice_out);
+ grpc_exec_ctx_finish(&exec_ctx);
+ return false;
+ } else if (r == Z_STREAM_END && ctx->flate == inflate) {
+ eoc = true;
+ }
+ if (ctx->zs.avail_in > 0) {
+ grpc_slice_buffer_undo_take_first(
+ in,
+ grpc_slice_sub(slice, GRPC_SLICE_LENGTH(slice) - ctx->zs.avail_in,
+ GRPC_SLICE_LENGTH(slice)));
+ }
+ grpc_slice_unref_internal(&exec_ctx, slice);
+ }
+ if (flush != 0 && ctx->zs.avail_out > 0 && !eoc) {
+ GPR_ASSERT(in->length == 0);
+ r = ctx->flate(&ctx->zs, flush);
+ if (flush == Z_SYNC_FLUSH) {
+ switch (r) {
+ case Z_OK:
+ /* Maybe flush is not complete; just made some partial progress. */
+ if (ctx->zs.avail_out > 0) {
+ flush = 0;
+ }
+ break;
+ case Z_BUF_ERROR:
+ case Z_STREAM_END:
+ flush = 0;
+ break;
+ default:
+ gpr_log(GPR_ERROR, "zlib error (%d)", r);
+ grpc_slice_unref_internal(&exec_ctx, slice_out);
+ grpc_exec_ctx_finish(&exec_ctx);
+ return false;
+ }
+ } else if (flush == Z_FINISH) {
+ switch (r) {
+ case Z_OK:
+ case Z_BUF_ERROR:
+ /* Wait for the next loop to assign additional output space. */
+ GPR_ASSERT(ctx->zs.avail_out == 0);
+ break;
+ case Z_STREAM_END:
+ flush = 0;
+ break;
+ default:
+ gpr_log(GPR_ERROR, "zlib error (%d)", r);
+ grpc_slice_unref_internal(&exec_ctx, slice_out);
+ grpc_exec_ctx_finish(&exec_ctx);
+ return false;
+ }
+ }
+ }
+
+ if (ctx->zs.avail_out == 0) {
+ grpc_slice_buffer_add(out, slice_out);
+ } else if (ctx->zs.avail_out < slice_size) {
+ slice_out.data.refcounted.length -= ctx->zs.avail_out;
+ grpc_slice_buffer_add(out, slice_out);
+ } else {
+ grpc_slice_unref_internal(&exec_ctx, slice_out);
+ }
+ max_output_size -= (slice_size - ctx->zs.avail_out);
+ }
+ grpc_exec_ctx_finish(&exec_ctx);
+ if (end_of_context) {
+ *end_of_context = eoc;
+ }
+ if (output_size) {
+ *output_size = original_max_output_size - max_output_size;
+ }
+ return true;
+}
+
+bool grpc_stream_compress(grpc_stream_compression_context *ctx,
+ grpc_slice_buffer *in, grpc_slice_buffer *out,
+ size_t *output_size, size_t max_output_size,
+ grpc_stream_compression_flush flush) {
+ GPR_ASSERT(ctx->flate == deflate);
+ int gzip_flush;
+ switch (flush) {
+ case GRPC_STREAM_COMPRESSION_FLUSH_NONE:
+ gzip_flush = 0;
+ break;
+ case GRPC_STREAM_COMPRESSION_FLUSH_SYNC:
+ gzip_flush = Z_SYNC_FLUSH;
+ break;
+ case GRPC_STREAM_COMPRESSION_FLUSH_FINISH:
+ gzip_flush = Z_FINISH;
+ break;
+ default:
+ gzip_flush = 0;
+ }
+ return gzip_flate(ctx, in, out, output_size, max_output_size, gzip_flush,
+ NULL);
+}
+
+bool grpc_stream_decompress(grpc_stream_compression_context *ctx,
+ grpc_slice_buffer *in, grpc_slice_buffer *out,
+ size_t *output_size, size_t max_output_size,
+ bool *end_of_context) {
+ GPR_ASSERT(ctx->flate == inflate);
+ return gzip_flate(ctx, in, out, output_size, max_output_size, Z_SYNC_FLUSH,
+ end_of_context);
+}
+
+grpc_stream_compression_context *grpc_stream_compression_context_create(
+ grpc_stream_compression_method method) {
+ grpc_stream_compression_context *ctx =
+ gpr_zalloc(sizeof(grpc_stream_compression_context));
+ int r;
+ if (ctx == NULL) {
+ return NULL;
+ }
+ if (method == GRPC_STREAM_COMPRESSION_DECOMPRESS) {
+ r = inflateInit2(&ctx->zs, 0x1F);
+ ctx->flate = inflate;
+ } else {
+ r = deflateInit2(&ctx->zs, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 0x1F, 8,
+ Z_DEFAULT_STRATEGY);
+ ctx->flate = deflate;
+ }
+ if (r != Z_OK) {
+ gpr_free(ctx);
+ return NULL;
+ }
+
+ return ctx;
+}
+
+void grpc_stream_compression_context_destroy(
+ grpc_stream_compression_context *ctx) {
+ if (ctx->flate == inflate) {
+ inflateEnd(&ctx->zs);
+ } else {
+ deflateEnd(&ctx->zs);
+ }
+ gpr_free(ctx);
+}
diff --git a/src/core/lib/compression/stream_compression.h b/src/core/lib/compression/stream_compression.h
new file mode 100644
index 00000000000..844dff81a3b
--- /dev/null
+++ b/src/core/lib/compression/stream_compression.h
@@ -0,0 +1,90 @@
+/*
+ *
+ * Copyright 2017 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_COMPRESSION_STREAM_COMPRESSION_H
+#define GRPC_CORE_LIB_COMPRESSION_STREAM_COMPRESSION_H
+
+#include
+
+#include
+#include
+
+/* Stream compression/decompression context */
+typedef struct grpc_stream_compression_context {
+ z_stream zs;
+ int (*flate)(z_stream *zs, int flush);
+} grpc_stream_compression_context;
+
+typedef enum grpc_stream_compression_method {
+ GRPC_STREAM_COMPRESSION_COMPRESS = 0,
+ GRPC_STREAM_COMPRESSION_DECOMPRESS,
+ GRPC_STREAM_COMPRESSION_METHOD_COUNT
+} grpc_stream_compression_method;
+
+typedef enum grpc_stream_compression_flush {
+ GRPC_STREAM_COMPRESSION_FLUSH_NONE = 0,
+ GRPC_STREAM_COMPRESSION_FLUSH_SYNC,
+ GRPC_STREAM_COMPRESSION_FLUSH_FINISH,
+ GRPC_STREAM_COMPRESSION_FLUSH_COUNT
+} grpc_stream_compression_flush;
+
+/**
+ * Compress bytes provided in \a in with a given context, with an optional flush
+ * at the end of compression. Emits at most \a max_output_size compressed bytes
+ * into \a out. If all the bytes in input buffer \a in are depleted and \a flush
+ * is not GRPC_STREAM_COMPRESSION_FLUSH_NONE, the corresponding flush method is
+ * executed. The total number of bytes emitted is outputed in \a output_size.
+ *
+ * A SYNC flush indicates that the entire messages in \a in can be decompressed
+ * from \a out. A FINISH flush implies a SYNC flush, and that any further
+ * compression will not be dependent on the state of the current context and any
+ * previous compressed bytes. It allows corresponding decompression context to
+ * be dropped when reaching this boundary.
+ */
+bool grpc_stream_compress(grpc_stream_compression_context *ctx,
+ grpc_slice_buffer *in, grpc_slice_buffer *out,
+ size_t *output_size, size_t max_output_size,
+ grpc_stream_compression_flush flush);
+
+/**
+ * Decompress bytes provided in \a in with a given context. Emits at most \a
+ * max_output_size decompressed bytes into \a out. If decompression process
+ * reached the end of a gzip stream, \a end_of_context is set to true; otherwise
+ * it is set to false. The total number of bytes emitted is outputed in \a
+ * output_size.
+ */
+bool grpc_stream_decompress(grpc_stream_compression_context *ctx,
+ grpc_slice_buffer *in, grpc_slice_buffer *out,
+ size_t *output_size, size_t max_output_size,
+ bool *end_of_context);
+
+/**
+ * Creates a stream compression context. \a pending_bytes_buffer is the input
+ * buffer for compression/decompression operations. \a method specifies whether
+ * the context is for compression or decompression.
+ */
+grpc_stream_compression_context *grpc_stream_compression_context_create(
+ grpc_stream_compression_method method);
+
+/**
+ * Destroys a stream compression context.
+ */
+void grpc_stream_compression_context_destroy(
+ grpc_stream_compression_context *ctx);
+
+#endif
diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py
index b30d340ce56..e7f7332b995 100644
--- a/src/python/grpcio/grpc_core_dependencies.py
+++ b/src/python/grpcio/grpc_core_dependencies.py
@@ -71,6 +71,7 @@ CORE_SOURCE_FILES = [
'src/core/lib/channel/handshaker_registry.c',
'src/core/lib/compression/compression.c',
'src/core/lib/compression/message_compress.c',
+ 'src/core/lib/compression/stream_compression.c',
'src/core/lib/http/format_request.c',
'src/core/lib/http/httpcli.c',
'src/core/lib/http/parser.c',
diff --git a/test/core/compression/stream_compression_test.c b/test/core/compression/stream_compression_test.c
new file mode 100644
index 00000000000..e576507aaf6
--- /dev/null
+++ b/test/core/compression/stream_compression_test.c
@@ -0,0 +1,292 @@
+/*
+ *
+ * Copyright 2017 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include
+
+#include
+#include
+#include
+#include
+
+#include "src/core/lib/compression/stream_compression.h"
+
+static void generate_random_payload(char *payload, size_t size) {
+ size_t i;
+ static const char chars[] = "abcdefghijklmnopqrstuvwxyz1234567890";
+ for (i = 0; i < size - 1; ++i) {
+ payload[i] = chars[rand() % (int)(sizeof(chars) - 1)];
+ }
+ payload[size - 1] = '\0';
+}
+
+static bool slice_buffer_equals_string(grpc_slice_buffer *buf,
+ const char *str) {
+ size_t i;
+ if (buf->length != strlen(str)) {
+ return false;
+ }
+ size_t pointer = 0;
+ for (i = 0; i < buf->count; i++) {
+ size_t slice_len = GRPC_SLICE_LENGTH(buf->slices[i]);
+ if (0 != strncmp(str + pointer,
+ (char *)GRPC_SLICE_START_PTR(buf->slices[i]), slice_len)) {
+ return false;
+ }
+ pointer += slice_len;
+ }
+ return true;
+}
+
+static void test_stream_compression_simple_compress_decompress() {
+ const char test_str[] = "aaaaaaabbbbbbbccccccctesttesttest";
+ grpc_slice_buffer source, relay, sink;
+ grpc_slice_buffer_init(&source);
+ grpc_slice_buffer_init(&relay);
+ grpc_slice_buffer_init(&sink);
+ grpc_stream_compression_context *compress_ctx =
+ grpc_stream_compression_context_create(GRPC_STREAM_COMPRESSION_COMPRESS);
+ grpc_stream_compression_context *decompress_ctx =
+ grpc_stream_compression_context_create(
+ GRPC_STREAM_COMPRESSION_DECOMPRESS);
+ grpc_slice slice = grpc_slice_from_static_string(test_str);
+ grpc_slice_buffer_add(&source, slice);
+ GPR_ASSERT(grpc_stream_compress(compress_ctx, &source, &relay, NULL,
+ ~(size_t)0,
+ GRPC_STREAM_COMPRESSION_FLUSH_FINISH));
+ bool end_of_context;
+ size_t output_size;
+ GPR_ASSERT(grpc_stream_decompress(decompress_ctx, &relay, &sink, &output_size,
+ ~(size_t)0, &end_of_context));
+ GPR_ASSERT(output_size == sizeof(test_str) - 1);
+ grpc_stream_compression_context_destroy(compress_ctx);
+ grpc_stream_compression_context_destroy(decompress_ctx);
+
+ GPR_ASSERT(slice_buffer_equals_string(&sink, test_str));
+
+ grpc_slice_buffer_destroy(&source);
+ grpc_slice_buffer_destroy(&relay);
+ grpc_slice_buffer_destroy(&sink);
+}
+
+static void
+test_stream_compression_simple_compress_decompress_with_output_size_constraint() {
+ const char test_str[] = "aaaaaaabbbbbbbccccccctesttesttest";
+ grpc_slice_buffer source, relay, sink;
+ grpc_slice_buffer_init(&source);
+ grpc_slice_buffer_init(&relay);
+ grpc_slice_buffer_init(&sink);
+ grpc_stream_compression_context *compress_ctx =
+ grpc_stream_compression_context_create(GRPC_STREAM_COMPRESSION_COMPRESS);
+ grpc_stream_compression_context *decompress_ctx =
+ grpc_stream_compression_context_create(
+ GRPC_STREAM_COMPRESSION_DECOMPRESS);
+ grpc_slice slice = grpc_slice_from_static_string(test_str);
+ grpc_slice_buffer_add(&source, slice);
+ GPR_ASSERT(grpc_stream_compress(compress_ctx, &source, &relay, NULL,
+ ~(size_t)0,
+ GRPC_STREAM_COMPRESSION_FLUSH_FINISH));
+ grpc_stream_compression_context_destroy(compress_ctx);
+
+ bool end_of_context;
+ size_t output_size;
+ size_t max_output_size = 2;
+ GPR_ASSERT(grpc_stream_decompress(decompress_ctx, &relay, &sink, &output_size,
+ max_output_size, &end_of_context));
+ GPR_ASSERT(output_size == max_output_size);
+ GPR_ASSERT(end_of_context == false);
+ grpc_slice slice_recv = grpc_slice_buffer_take_first(&sink);
+ char *str_recv = (char *)GRPC_SLICE_START_PTR(slice_recv);
+ GPR_ASSERT(GRPC_SLICE_LENGTH(slice_recv) == max_output_size);
+ GPR_ASSERT(0 == strncmp(test_str, str_recv, max_output_size));
+ grpc_slice_unref(slice_recv);
+
+ size_t remaining_size = sizeof(test_str) - 1 - max_output_size;
+ GPR_ASSERT(grpc_stream_decompress(decompress_ctx, &relay, &sink, &output_size,
+ remaining_size, &end_of_context));
+ GPR_ASSERT(output_size == remaining_size);
+ GPR_ASSERT(end_of_context == true);
+
+ GPR_ASSERT(slice_buffer_equals_string(&sink, test_str + max_output_size));
+
+ grpc_stream_compression_context_destroy(decompress_ctx);
+ grpc_slice_buffer_destroy(&source);
+ grpc_slice_buffer_destroy(&relay);
+ grpc_slice_buffer_destroy(&sink);
+}
+
+#define LARGE_DATA_SIZE (1024 * 1024)
+static void
+test_stream_compression_simple_compress_decompress_with_large_data() {
+ char *test_str = gpr_malloc(LARGE_DATA_SIZE * sizeof(char));
+ generate_random_payload(test_str, LARGE_DATA_SIZE);
+ grpc_slice_buffer source, relay, sink;
+ grpc_slice_buffer_init(&source);
+ grpc_slice_buffer_init(&relay);
+ grpc_slice_buffer_init(&sink);
+ grpc_stream_compression_context *compress_ctx =
+ grpc_stream_compression_context_create(GRPC_STREAM_COMPRESSION_COMPRESS);
+ grpc_stream_compression_context *decompress_ctx =
+ grpc_stream_compression_context_create(
+ GRPC_STREAM_COMPRESSION_DECOMPRESS);
+ grpc_slice slice = grpc_slice_from_static_string(test_str);
+ grpc_slice_buffer_add(&source, slice);
+ GPR_ASSERT(grpc_stream_compress(compress_ctx, &source, &relay, NULL,
+ ~(size_t)0,
+ GRPC_STREAM_COMPRESSION_FLUSH_FINISH));
+ bool end_of_context;
+ size_t output_size;
+ GPR_ASSERT(grpc_stream_decompress(decompress_ctx, &relay, &sink, &output_size,
+ ~(size_t)0, &end_of_context));
+ GPR_ASSERT(output_size == LARGE_DATA_SIZE - 1);
+ grpc_stream_compression_context_destroy(compress_ctx);
+ grpc_stream_compression_context_destroy(decompress_ctx);
+
+ GPR_ASSERT(slice_buffer_equals_string(&sink, test_str));
+
+ grpc_slice_buffer_destroy(&source);
+ grpc_slice_buffer_destroy(&relay);
+ grpc_slice_buffer_destroy(&sink);
+ gpr_free(test_str);
+}
+
+static void test_stream_compression_drop_context() {
+ const char test_str[] = "aaaaaaabbbbbbbccccccc";
+ const char test_str2[] = "dddddddeeeeeeefffffffggggg";
+ grpc_slice_buffer source, relay, sink;
+ grpc_slice_buffer_init(&source);
+ grpc_slice_buffer_init(&relay);
+ grpc_slice_buffer_init(&sink);
+ grpc_stream_compression_context *compress_ctx =
+ grpc_stream_compression_context_create(GRPC_STREAM_COMPRESSION_COMPRESS);
+ grpc_slice slice = grpc_slice_from_static_string(test_str);
+ grpc_slice_buffer_add(&source, slice);
+ GPR_ASSERT(grpc_stream_compress(compress_ctx, &source, &relay, NULL,
+ ~(size_t)0,
+ GRPC_STREAM_COMPRESSION_FLUSH_FINISH));
+ grpc_stream_compression_context_destroy(compress_ctx);
+
+ compress_ctx =
+ grpc_stream_compression_context_create(GRPC_STREAM_COMPRESSION_COMPRESS);
+ slice = grpc_slice_from_static_string(test_str2);
+ grpc_slice_buffer_add(&source, slice);
+ GPR_ASSERT(grpc_stream_compress(compress_ctx, &source, &relay, NULL,
+ ~(size_t)0,
+ GRPC_STREAM_COMPRESSION_FLUSH_FINISH));
+ grpc_stream_compression_context_destroy(compress_ctx);
+
+ /* Concatenate the two compressed sliced into one to test decompressing two
+ * contexts */
+ grpc_slice slice1 = grpc_slice_buffer_take_first(&relay);
+ grpc_slice slice2 = grpc_slice_buffer_take_first(&relay);
+ grpc_slice slice3 =
+ grpc_slice_malloc(GRPC_SLICE_LENGTH(slice1) + GRPC_SLICE_LENGTH(slice2));
+ memcpy(GRPC_SLICE_START_PTR(slice3), GRPC_SLICE_START_PTR(slice1),
+ GRPC_SLICE_LENGTH(slice1));
+ memcpy(GRPC_SLICE_START_PTR(slice3) + GRPC_SLICE_LENGTH(slice1),
+ GRPC_SLICE_START_PTR(slice2), GRPC_SLICE_LENGTH(slice2));
+ grpc_slice_unref(slice1);
+ grpc_slice_unref(slice2);
+ grpc_slice_buffer_add(&relay, slice3);
+
+ grpc_stream_compression_context *decompress_ctx =
+ grpc_stream_compression_context_create(
+ GRPC_STREAM_COMPRESSION_DECOMPRESS);
+ bool end_of_context;
+ size_t output_size;
+ GPR_ASSERT(grpc_stream_decompress(decompress_ctx, &relay, &sink, &output_size,
+ ~(size_t)0, &end_of_context));
+ GPR_ASSERT(end_of_context == true);
+ GPR_ASSERT(output_size == sizeof(test_str) - 1);
+
+ GPR_ASSERT(slice_buffer_equals_string(&sink, test_str));
+ grpc_stream_compression_context_destroy(decompress_ctx);
+ grpc_slice_buffer_destroy(&sink);
+
+ grpc_slice_buffer_init(&sink);
+ decompress_ctx = grpc_stream_compression_context_create(
+ GRPC_STREAM_COMPRESSION_DECOMPRESS);
+ GPR_ASSERT(grpc_stream_decompress(decompress_ctx, &relay, &sink, &output_size,
+ ~(size_t)0, &end_of_context));
+ GPR_ASSERT(end_of_context == true);
+ GPR_ASSERT(output_size == sizeof(test_str2) - 1);
+ GPR_ASSERT(slice_buffer_equals_string(&sink, test_str2));
+ grpc_stream_compression_context_destroy(decompress_ctx);
+
+ grpc_slice_buffer_destroy(&source);
+ grpc_slice_buffer_destroy(&relay);
+ grpc_slice_buffer_destroy(&sink);
+}
+
+static void test_stream_compression_sync_flush() {
+ const char test_str[] = "aaaaaaabbbbbbbccccccc";
+ const char test_str2[] = "dddddddeeeeeeefffffffggggg";
+ grpc_slice_buffer source, relay, sink;
+ grpc_slice_buffer_init(&source);
+ grpc_slice_buffer_init(&relay);
+ grpc_slice_buffer_init(&sink);
+ grpc_stream_compression_context *compress_ctx =
+ grpc_stream_compression_context_create(GRPC_STREAM_COMPRESSION_COMPRESS);
+ grpc_slice slice = grpc_slice_from_static_string(test_str);
+ grpc_slice_buffer_add(&source, slice);
+ GPR_ASSERT(grpc_stream_compress(compress_ctx, &source, &relay, NULL,
+ ~(size_t)0,
+ GRPC_STREAM_COMPRESSION_FLUSH_SYNC));
+
+ grpc_stream_compression_context *decompress_ctx =
+ grpc_stream_compression_context_create(
+ GRPC_STREAM_COMPRESSION_DECOMPRESS);
+ bool end_of_context;
+ size_t output_size;
+ GPR_ASSERT(grpc_stream_decompress(decompress_ctx, &relay, &sink, &output_size,
+ ~(size_t)0, &end_of_context));
+ GPR_ASSERT(end_of_context == false);
+ GPR_ASSERT(output_size == sizeof(test_str) - 1);
+ GPR_ASSERT(slice_buffer_equals_string(&sink, test_str));
+ grpc_slice_buffer_destroy(&sink);
+
+ grpc_slice_buffer_init(&sink);
+ slice = grpc_slice_from_static_string(test_str2);
+ grpc_slice_buffer_add(&source, slice);
+ GPR_ASSERT(grpc_stream_compress(compress_ctx, &source, &relay, NULL,
+ ~(size_t)0,
+ GRPC_STREAM_COMPRESSION_FLUSH_FINISH));
+ grpc_stream_compression_context_destroy(compress_ctx);
+
+ GPR_ASSERT(grpc_stream_decompress(decompress_ctx, &relay, &sink, &output_size,
+ ~(size_t)0, &end_of_context));
+ GPR_ASSERT(end_of_context == true);
+ GPR_ASSERT(output_size == sizeof(test_str2) - 1);
+ GPR_ASSERT(slice_buffer_equals_string(&sink, test_str2));
+ grpc_stream_compression_context_destroy(decompress_ctx);
+
+ grpc_slice_buffer_destroy(&source);
+ grpc_slice_buffer_destroy(&relay);
+ grpc_slice_buffer_destroy(&sink);
+}
+
+int main(int argc, char **argv) {
+ grpc_init();
+ test_stream_compression_simple_compress_decompress();
+ test_stream_compression_simple_compress_decompress_with_output_size_constraint();
+ test_stream_compression_simple_compress_decompress_with_large_data();
+ test_stream_compression_sync_flush();
+ test_stream_compression_drop_context();
+ grpc_shutdown();
+
+ return 0;
+}
diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal
index 4c6c656b1b5..7c1e75a99cd 100644
--- a/tools/doxygen/Doxyfile.core.internal
+++ b/tools/doxygen/Doxyfile.core.internal
@@ -1071,6 +1071,8 @@ src/core/lib/compression/algorithm_metadata.h \
src/core/lib/compression/compression.c \
src/core/lib/compression/message_compress.c \
src/core/lib/compression/message_compress.h \
+src/core/lib/compression/stream_compression.c \
+src/core/lib/compression/stream_compression.h \
src/core/lib/debug/trace.c \
src/core/lib/debug/trace.h \
src/core/lib/http/format_request.c \
diff --git a/tools/run_tests/generated/sources_and_headers.json b/tools/run_tests/generated/sources_and_headers.json
index 0a91a0cec45..c7cc9cb6945 100644
--- a/tools/run_tests/generated/sources_and_headers.json
+++ b/tools/run_tests/generated/sources_and_headers.json
@@ -2163,6 +2163,23 @@
"third_party": false,
"type": "target"
},
+ {
+ "deps": [
+ "gpr",
+ "gpr_test_util",
+ "grpc",
+ "grpc_test_util"
+ ],
+ "headers": [],
+ "is_filegroup": false,
+ "language": "c",
+ "name": "stream_compression_test",
+ "src": [
+ "test/core/compression/stream_compression_test.c"
+ ],
+ "third_party": false,
+ "type": "target"
+ },
{
"deps": [
"gpr",
@@ -7672,6 +7689,7 @@
"src/core/lib/channel/handshaker_registry.h",
"src/core/lib/compression/algorithm_metadata.h",
"src/core/lib/compression/message_compress.h",
+ "src/core/lib/compression/stream_compression.h",
"src/core/lib/http/format_request.h",
"src/core/lib/http/httpcli.h",
"src/core/lib/http/parser.h",
@@ -7806,6 +7824,8 @@
"src/core/lib/compression/compression.c",
"src/core/lib/compression/message_compress.c",
"src/core/lib/compression/message_compress.h",
+ "src/core/lib/compression/stream_compression.c",
+ "src/core/lib/compression/stream_compression.h",
"src/core/lib/http/format_request.c",
"src/core/lib/http/format_request.h",
"src/core/lib/http/httpcli.c",
diff --git a/tools/run_tests/generated/tests.json b/tools/run_tests/generated/tests.json
index 82437c94cb5..d24209506a7 100644
--- a/tools/run_tests/generated/tests.json
+++ b/tools/run_tests/generated/tests.json
@@ -2271,6 +2271,28 @@
"windows"
]
},
+ {
+ "args": [],
+ "ci_platforms": [
+ "linux",
+ "mac",
+ "posix",
+ "windows"
+ ],
+ "cpu_cost": 1.0,
+ "exclude_configs": [],
+ "exclude_iomgrs": [],
+ "flaky": false,
+ "gtest": false,
+ "language": "c",
+ "name": "stream_compression_test",
+ "platforms": [
+ "linux",
+ "mac",
+ "posix",
+ "windows"
+ ]
+ },
{
"args": [],
"ci_platforms": [
diff --git a/tools/ubsan_suppressions.txt b/tools/ubsan_suppressions.txt
index 83dcfc3d058..2dcfeea9afa 100644
--- a/tools/ubsan_suppressions.txt
+++ b/tools/ubsan_suppressions.txt
@@ -7,3 +7,4 @@ alignment:CRYPTO_cbc128_encrypt
alignment:CRYPTO_gcm128_encrypt
nonnull-attribute:google::protobuf::*
alignment:google::protobuf::*
+nonnull-attribute:_tr_stored_block
diff --git a/vsprojects/buildtests_c.sln b/vsprojects/buildtests_c.sln
index 3bcc832db00..55de734b427 100644
--- a/vsprojects/buildtests_c.sln
+++ b/vsprojects/buildtests_c.sln
@@ -1585,6 +1585,17 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "status_conversion_test", "v
{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
EndProjectSection
EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "stream_compression_test", "vcxproj\test\stream_compression_test\stream_compression_test.vcxproj", "{A5EE72A2-656C-0896-12F3-A92583CF7C61}"
+ ProjectSection(myProperties) = preProject
+ lib = "False"
+ EndProjectSection
+ ProjectSection(ProjectDependencies) = postProject
+ {17BCAFC0-5FDC-4C94-AEB9-95F3E220614B} = {17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}
+ {29D16885-7228-4C31-81ED-5F9187C7F2A9} = {29D16885-7228-4C31-81ED-5F9187C7F2A9}
+ {EAB0A629-17A9-44DB-B5FF-E91A721FE037} = {EAB0A629-17A9-44DB-B5FF-E91A721FE037}
+ {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
+ EndProjectSection
+EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "stream_owned_slice_test", "vcxproj\test\stream_owned_slice_test\stream_owned_slice_test.vcxproj", "{D5A20C05-D9B2-970B-8429-94BC3F58D1C4}"
ProjectSection(myProperties) = preProject
lib = "False"
@@ -4121,6 +4132,22 @@ Global
{21E2A241-9D48-02CD-92E4-4EEC98424CF5}.Release-DLL|Win32.Build.0 = Release|Win32
{21E2A241-9D48-02CD-92E4-4EEC98424CF5}.Release-DLL|x64.ActiveCfg = Release|x64
{21E2A241-9D48-02CD-92E4-4EEC98424CF5}.Release-DLL|x64.Build.0 = Release|x64
+ {A5EE72A2-656C-0896-12F3-A92583CF7C61}.Debug|Win32.ActiveCfg = Debug|Win32
+ {A5EE72A2-656C-0896-12F3-A92583CF7C61}.Debug|x64.ActiveCfg = Debug|x64
+ {A5EE72A2-656C-0896-12F3-A92583CF7C61}.Release|Win32.ActiveCfg = Release|Win32
+ {A5EE72A2-656C-0896-12F3-A92583CF7C61}.Release|x64.ActiveCfg = Release|x64
+ {A5EE72A2-656C-0896-12F3-A92583CF7C61}.Debug|Win32.Build.0 = Debug|Win32
+ {A5EE72A2-656C-0896-12F3-A92583CF7C61}.Debug|x64.Build.0 = Debug|x64
+ {A5EE72A2-656C-0896-12F3-A92583CF7C61}.Release|Win32.Build.0 = Release|Win32
+ {A5EE72A2-656C-0896-12F3-A92583CF7C61}.Release|x64.Build.0 = Release|x64
+ {A5EE72A2-656C-0896-12F3-A92583CF7C61}.Debug-DLL|Win32.ActiveCfg = Debug|Win32
+ {A5EE72A2-656C-0896-12F3-A92583CF7C61}.Debug-DLL|Win32.Build.0 = Debug|Win32
+ {A5EE72A2-656C-0896-12F3-A92583CF7C61}.Debug-DLL|x64.ActiveCfg = Debug|x64
+ {A5EE72A2-656C-0896-12F3-A92583CF7C61}.Debug-DLL|x64.Build.0 = Debug|x64
+ {A5EE72A2-656C-0896-12F3-A92583CF7C61}.Release-DLL|Win32.ActiveCfg = Release|Win32
+ {A5EE72A2-656C-0896-12F3-A92583CF7C61}.Release-DLL|Win32.Build.0 = Release|Win32
+ {A5EE72A2-656C-0896-12F3-A92583CF7C61}.Release-DLL|x64.ActiveCfg = Release|x64
+ {A5EE72A2-656C-0896-12F3-A92583CF7C61}.Release-DLL|x64.Build.0 = Release|x64
{D5A20C05-D9B2-970B-8429-94BC3F58D1C4}.Debug|Win32.ActiveCfg = Debug|Win32
{D5A20C05-D9B2-970B-8429-94BC3F58D1C4}.Debug|x64.ActiveCfg = Debug|x64
{D5A20C05-D9B2-970B-8429-94BC3F58D1C4}.Release|Win32.ActiveCfg = Release|Win32
diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj b/vsprojects/vcxproj/grpc/grpc.vcxproj
index 112f3ec30ac..dbc148e0f81 100644
--- a/vsprojects/vcxproj/grpc/grpc.vcxproj
+++ b/vsprojects/vcxproj/grpc/grpc.vcxproj
@@ -311,6 +311,7 @@
+
@@ -540,6 +541,8 @@
+
+
diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters
index 5c29e58badb..45d11933c1a 100644
--- a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters
@@ -31,6 +31,9 @@
src\core\lib\compression
+
+ src\core\lib\compression
+
src\core\lib\http
@@ -884,6 +887,9 @@
src\core\lib\compression
+
+ src\core\lib\compression
+
src\core\lib\http
diff --git a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj
index 1899be91db3..32809ca5899 100644
--- a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj
+++ b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj
@@ -206,6 +206,7 @@
+
@@ -366,6 +367,8 @@
+
+
diff --git a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters
index 9c81fc5bf51..def8de42028 100644
--- a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters
@@ -88,6 +88,9 @@
src\core\lib\compression
+
+ src\core\lib\compression
+
src\core\lib\http
@@ -611,6 +614,9 @@
src\core\lib\compression
+
+ src\core\lib\compression
+
src\core\lib\http
diff --git a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
index 730ac01ea3a..ac98dc05401 100644
--- a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
+++ b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
@@ -301,6 +301,7 @@
+
@@ -507,6 +508,8 @@
+
+
diff --git a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters
index 427352eb3b0..fea68c51dc8 100644
--- a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters
@@ -34,6 +34,9 @@
src\core\lib\compression
+
+ src\core\lib\compression
+
src\core\lib\http
@@ -794,6 +797,9 @@
src\core\lib\compression
+
+ src\core\lib\compression
+
src\core\lib\http
diff --git a/vsprojects/vcxproj/test/stream_compression_test/stream_compression_test.vcxproj b/vsprojects/vcxproj/test/stream_compression_test/stream_compression_test.vcxproj
new file mode 100644
index 00000000000..7faf665b20d
--- /dev/null
+++ b/vsprojects/vcxproj/test/stream_compression_test/stream_compression_test.vcxproj
@@ -0,0 +1,199 @@
+
+
+
+
+
+ Debug
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ Win32
+
+
+ Release
+ x64
+
+
+
+ {A5EE72A2-656C-0896-12F3-A92583CF7C61}
+ true
+ $(SolutionDir)IntDir\$(MSBuildProjectName)\
+
+
+
+ v100
+
+
+ v110
+
+
+ v120
+
+
+ v140
+
+
+ Application
+ true
+ Unicode
+
+
+ Application
+ false
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+ stream_compression_test
+ static
+ Debug
+ static
+ Debug
+
+
+ stream_compression_test
+ static
+ Release
+ static
+ Release
+
+
+
+ NotUsing
+ Level3
+ Disabled
+ WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)
+ true
+ MultiThreadedDebug
+ true
+ None
+ false
+
+
+ Console
+ true
+ false
+
+
+
+
+
+ NotUsing
+ Level3
+ Disabled
+ WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)
+ true
+ MultiThreadedDebug
+ true
+ None
+ false
+
+
+ Console
+ true
+ false
+
+
+
+
+
+ NotUsing
+ Level3
+ MaxSpeed
+ WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)
+ true
+ true
+ true
+ MultiThreaded
+ true
+ None
+ false
+
+
+ Console
+ true
+ false
+ true
+ true
+
+
+
+
+
+ NotUsing
+ Level3
+ MaxSpeed
+ WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)
+ true
+ true
+ true
+ MultiThreaded
+ true
+ None
+ false
+
+
+ Console
+ true
+ false
+ true
+ true
+
+
+
+
+
+
+
+
+
+ {17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}
+
+
+ {29D16885-7228-4C31-81ED-5F9187C7F2A9}
+
+
+ {EAB0A629-17A9-44DB-B5FF-E91A721FE037}
+
+
+ {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
+
+
+
+
+
+
+
+
+
diff --git a/vsprojects/vcxproj/test/stream_compression_test/stream_compression_test.vcxproj.filters b/vsprojects/vcxproj/test/stream_compression_test/stream_compression_test.vcxproj.filters
new file mode 100644
index 00000000000..a63628279da
--- /dev/null
+++ b/vsprojects/vcxproj/test/stream_compression_test/stream_compression_test.vcxproj.filters
@@ -0,0 +1,21 @@
+
+
+
+
+ test\core\compression
+
+
+
+
+
+ {22ec1dc6-29e1-32ac-1494-43bb7f211422}
+
+
+ {62cac7ff-76a5-35ff-1e73-a8508e826ba3}
+
+
+ {02c8e4fc-eeda-2f58-227f-ebef22a39562}
+
+
+
+