diff --git a/BUILD b/BUILD
index 6f92ef3858fe34d6850ab020449bad32f370d7b5..9f1ab2a5384a09bb0effd22da8b11812d7efb25d 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 6ee9490c25011fe10a4ce66c6a39a3c88e091534..5413bbcc0f3719088d991149f0f2dd72119ffc5c 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 72468f8f9286f8b7938ff857fb4cea11f673b742..210d6768222e15a49cc11057135ac164e322a2f0 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 00fbe70fee8fcabb30830497a3b364ff3179b691..ae78d931f2d884404bf49e491932bb9a9d06879b 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 1b9eb63bcdc97c698dd41e6543c0594c471d2912..581fa65a235d82a47b4c6dfcdf7ae7e4dfd67e63 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 71e5776d8514663bc59195b62f6b7574db048d95..e214f9c5464eb63a2b84f67583b07a7b11d52462 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 cd374bae650f7441367d5029355f2c9295e7cfe9..6d50712fb543144bcc1dde293ed166e9d7dd573e 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 fc51a92daf80c2020187f2f8cc4951904821866c..cf3fc3598a28bf9b5c1f318b3b97277542c3910f 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 ab4a634c9b0e906d70cd4cba9e9c1c8a4e59335e..a87c113b04b17a4be8bac0139f92db69fe4c2dc3 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 602800b1b511f42e2e7156c6ad00ce79d9642626..256a21d017bd6a0a9e834cbc67f937244e362fd6 100644
--- a/package.xml
+++ b/package.xml
@@ -200,6 +200,7 @@
     <file baseinstalldir="/" name="src/core/lib/channel/handshaker_registry.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/compression/algorithm_metadata.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/compression/message_compress.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/compression/stream_compression.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/http/format_request.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/http/httpcli.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/http/parser.h" role="src" />
@@ -417,6 +418,7 @@
     <file baseinstalldir="/" name="src/core/lib/channel/handshaker_registry.c" role="src" />
     <file baseinstalldir="/" name="src/core/lib/compression/compression.c" role="src" />
     <file baseinstalldir="/" name="src/core/lib/compression/message_compress.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/compression/stream_compression.c" role="src" />
     <file baseinstalldir="/" name="src/core/lib/http/format_request.c" role="src" />
     <file baseinstalldir="/" name="src/core/lib/http/httpcli.c" role="src" />
     <file baseinstalldir="/" name="src/core/lib/http/parser.c" role="src" />
diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.c b/src/core/ext/transport/chttp2/transport/chttp2_transport.c
index bd25f69a1de0360d180fa23c6154699a64158866..731ebf400f75bdf7c2ae63b3d7665f2920606fbb 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 a5b67e5abaae3bc1dffba4de606730e64506d609..4563b78e755bdf3aea1602a76a4a44f9b85aab7c 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 0000000000000000000000000000000000000000..df13d53e06f2f9a748ea85dd7489e36547fab1f7
--- /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 <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+#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 0000000000000000000000000000000000000000..844dff81a3b05bbf4dad89f2b63fb64a0a866689
--- /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 <stdbool.h>
+
+#include <grpc/slice_buffer.h>
+#include <zlib.h>
+
+/* 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 b30d340ce569f497cd1e5fc4cd4468aacfbec90b..e7f7332b99508ab469a3a721f8eef82862d4f8bb 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 0000000000000000000000000000000000000000..e576507aaf66b04f89e623d952fb90f10abb153b
--- /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 <string.h>
+
+#include <grpc/grpc.h>
+#include <grpc/slice_buffer.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+#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 4c6c656b1b54c029e7c2746d5f85adbb2dd697c8..7c1e75a99cdd1d038e1cbe1ae674345d6a51d5d6 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 0a91a0cec45e591c3e5144d5b8f8328344237be5..c7cc9cb6945bf5345996db3f73481f3f25ed942f 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 82437c94cb5276dd593d7ad7b763f2a33c7f7afd..d24209506a76c221a157052bab59ee65f8a00760 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 83dcfc3d0580dc17568cbb03ebb2d42b101e9e0b..2dcfeea9afae8718c722450858bf300123f06ccf 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 3bcc832db00056421e79e31d695d2cb00beb4525..55de734b427278d7837405b953ad15dd1b78190e 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 112f3ec30ac174c4ea34173f1e0f0fa7e33d2e65..dbc148e0f81a6335647798b4bd98a649b1ca0946 100644
--- a/vsprojects/vcxproj/grpc/grpc.vcxproj
+++ b/vsprojects/vcxproj/grpc/grpc.vcxproj
@@ -311,6 +311,7 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_registry.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\algorithm_metadata.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\message_compress.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\stream_compression.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\http\format_request.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\http\httpcli.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\http\parser.h" />
@@ -540,6 +541,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\message_compress.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\stream_compression.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\http\format_request.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\http\httpcli.c">
diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters
index 5c29e58badb49f9a55374b68b3eb870598bd34c8..45d11933c1a0ccdbd788e80f7df4896d7eeb02c6 100644
--- a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters
@@ -31,6 +31,9 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\message_compress.c">
       <Filter>src\core\lib\compression</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\stream_compression.c">
+      <Filter>src\core\lib\compression</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\http\format_request.c">
       <Filter>src\core\lib\http</Filter>
     </ClCompile>
@@ -884,6 +887,9 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\message_compress.h">
       <Filter>src\core\lib\compression</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\stream_compression.h">
+      <Filter>src\core\lib\compression</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\http\format_request.h">
       <Filter>src\core\lib\http</Filter>
     </ClInclude>
diff --git a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj
index 1899be91db37c78c545f28e6e6888a516cc4aca6..32809ca58999644fe43194f399d25b05805611b3 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 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_registry.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\algorithm_metadata.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\message_compress.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\stream_compression.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\http\format_request.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\http\httpcli.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\http\parser.h" />
@@ -366,6 +367,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\message_compress.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\stream_compression.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\http\format_request.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\http\httpcli.c">
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 9c81fc5bf5197b0e82d6de7628e79843209264d9..def8de420289917ab30fe41bedd69dbb1bca4977 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 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\message_compress.c">
       <Filter>src\core\lib\compression</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\stream_compression.c">
+      <Filter>src\core\lib\compression</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\http\format_request.c">
       <Filter>src\core\lib\http</Filter>
     </ClCompile>
@@ -611,6 +614,9 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\message_compress.h">
       <Filter>src\core\lib\compression</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\stream_compression.h">
+      <Filter>src\core\lib\compression</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\http\format_request.h">
       <Filter>src\core\lib\http</Filter>
     </ClInclude>
diff --git a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
index 730ac01ea3a6024af7de8b571fcbf5f32f580ba7..ac98dc054016421294f8f189a6141c7e5be6ccfd 100644
--- a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
+++ b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
@@ -301,6 +301,7 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_registry.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\algorithm_metadata.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\message_compress.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\stream_compression.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\http\format_request.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\http\httpcli.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\http\parser.h" />
@@ -507,6 +508,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\message_compress.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\stream_compression.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\http\format_request.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\http\httpcli.c">
diff --git a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters
index 427352eb3b0867516e3aa2466f8144b5c5a4843a..fea68c51dc88dc1ee80d45c5771f33e8def4a07b 100644
--- a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters
@@ -34,6 +34,9 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\message_compress.c">
       <Filter>src\core\lib\compression</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\stream_compression.c">
+      <Filter>src\core\lib\compression</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\http\format_request.c">
       <Filter>src\core\lib\http</Filter>
     </ClCompile>
@@ -794,6 +797,9 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\message_compress.h">
       <Filter>src\core\lib\compression</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\stream_compression.h">
+      <Filter>src\core\lib\compression</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\http\format_request.h">
       <Filter>src\core\lib\http</Filter>
     </ClInclude>
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 0000000000000000000000000000000000000000..7faf665b20d4827cdd9b8d5dbcde50fca10417eb
--- /dev/null
+++ b/vsprojects/vcxproj/test/stream_compression_test/stream_compression_test.vcxproj
@@ -0,0 +1,199 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\1.0.204.1.props')" />
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{A5EE72A2-656C-0896-12F3-A92583CF7C61}</ProjectGuid>
+    <IgnoreWarnIntDirInTempDetected>true</IgnoreWarnIntDirInTempDetected>
+    <IntDir>$(SolutionDir)IntDir\$(MSBuildProjectName)\</IntDir>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '10.0'" Label="Configuration">
+    <PlatformToolset>v100</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '11.0'" Label="Configuration">
+    <PlatformToolset>v110</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '12.0'" Label="Configuration">
+    <PlatformToolset>v120</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '14.0'" Label="Configuration">
+    <PlatformToolset>v140</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="$(SolutionDir)\..\vsprojects\global.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\openssl.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\winsock.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\zlib.props" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)'=='Debug'">
+    <TargetName>stream_compression_test</TargetName>
+    <Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib>
+    <Configuration-grpc_dependencies_zlib>Debug</Configuration-grpc_dependencies_zlib>
+    <Linkage-grpc_dependencies_openssl>static</Linkage-grpc_dependencies_openssl>
+    <Configuration-grpc_dependencies_openssl>Debug</Configuration-grpc_dependencies_openssl>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Release'">
+    <TargetName>stream_compression_test</TargetName>
+    <Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib>
+    <Configuration-grpc_dependencies_zlib>Release</Configuration-grpc_dependencies_zlib>
+    <Linkage-grpc_dependencies_openssl>static</Linkage-grpc_dependencies_openssl>
+    <Configuration-grpc_dependencies_openssl>Release</Configuration-grpc_dependencies_openssl>
+  </PropertyGroup>
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+
+  <ItemGroup>
+    <ClCompile Include="$(SolutionDir)\..\test\core\compression\stream_compression_test.c">
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc_test_util\grpc_test_util.vcxproj">
+      <Project>{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}</Project>
+    </ProjectReference>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc\grpc.vcxproj">
+      <Project>{29D16885-7228-4C31-81ED-5F9187C7F2A9}</Project>
+    </ProjectReference>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\gpr_test_util\gpr_test_util.vcxproj">
+      <Project>{EAB0A629-17A9-44DB-B5FF-E91A721FE037}</Project>
+    </ProjectReference>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\gpr\gpr.vcxproj">
+      <Project>{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}</Project>
+    </ProjectReference>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="packages.config" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies\grpc.dependencies.zlib.targets')" />
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies\grpc.dependencies.zlib.targets')" />
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies\grpc.dependencies.openssl.targets')" />
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies\grpc.dependencies.openssl.targets')" />
+  </ImportGroup>
+  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
+    <PropertyGroup>
+      <ErrorText>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}.</ErrorText>
+    </PropertyGroup>
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets')" />
+  </Target>
+</Project>
+
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 0000000000000000000000000000000000000000..a63628279dac5e0cabb9c82dbec86404afe7fa65
--- /dev/null
+++ b/vsprojects/vcxproj/test/stream_compression_test/stream_compression_test.vcxproj.filters
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <ClCompile Include="$(SolutionDir)\..\test\core\compression\stream_compression_test.c">
+      <Filter>test\core\compression</Filter>
+    </ClCompile>
+  </ItemGroup>
+
+  <ItemGroup>
+    <Filter Include="test">
+      <UniqueIdentifier>{22ec1dc6-29e1-32ac-1494-43bb7f211422}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test\core">
+      <UniqueIdentifier>{62cac7ff-76a5-35ff-1e73-a8508e826ba3}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test\core\compression">
+      <UniqueIdentifier>{02c8e4fc-eeda-2f58-227f-ebef22a39562}</UniqueIdentifier>
+    </Filter>
+  </ItemGroup>
+</Project>
+