Merge pull request #13829 from apolcyn/backport_bazel_changes

Backport bazel changes from #13468 to 1.8.x
diff --git a/BUILD b/BUILD
index df334cd..f48d6bc 100644
--- a/BUILD
+++ b/BUILD
@@ -41,9 +41,9 @@
 # This should be updated along with build.yaml
 g_stands_for = "generous"
 
-core_version = "5.0.0-dev"
+core_version = "5.0.0"
 
-version = "1.8.0-dev"
+version = "1.8.2"
 
 GPR_PUBLIC_HDRS = [
     "include/grpc/support/alloc.h",
@@ -79,10 +79,11 @@
     "include/grpc/byte_buffer.h",
     "include/grpc/byte_buffer_reader.h",
     "include/grpc/compression.h",
-    "include/grpc/load_reporting.h",
+    "include/grpc/fork.h",
     "include/grpc/grpc.h",
     "include/grpc/grpc_posix.h",
     "include/grpc/grpc_security_constants.h",
+    "include/grpc/load_reporting.h",
     "include/grpc/slice.h",
     "include/grpc/slice_buffer.h",
     "include/grpc/status.h",
diff --git a/CMakeLists.txt b/CMakeLists.txt
index d12d573..e99fce6 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -24,7 +24,7 @@
 cmake_minimum_required(VERSION 2.8)
 
 set(PACKAGE_NAME      "grpc")
-set(PACKAGE_VERSION   "1.8.0-pre2")
+set(PACKAGE_VERSION   "1.8.2")
 set(PACKAGE_STRING    "${PACKAGE_NAME} ${PACKAGE_VERSION}")
 set(PACKAGE_TARNAME   "${PACKAGE_NAME}-${PACKAGE_VERSION}")
 set(PACKAGE_BUGREPORT "https://github.com/grpc/grpc/issues/")
diff --git a/Makefile b/Makefile
index d7e7012..3f4452a 100644
--- a/Makefile
+++ b/Makefile
@@ -411,9 +411,9 @@
 Q = @
 endif
 
-CORE_VERSION = 5.0.0-pre2
-CPP_VERSION = 1.8.0-pre2
-CSHARP_VERSION = 1.8.0-pre2
+CORE_VERSION = 5.0.0
+CPP_VERSION = 1.8.2
+CSHARP_VERSION = 1.8.2
 
 CPPFLAGS_NO_ARCH += $(addprefix -I, $(INCLUDES)) $(addprefix -D, $(DEFINES))
 CPPFLAGS += $(CPPFLAGS_NO_ARCH) $(ARCH_FLAGS)
diff --git a/README.md b/README.md
index 048614a..1550bb5 100644
--- a/README.md
+++ b/README.md
@@ -27,13 +27,13 @@
 
 | Language                | Source                              | Status  |
 |-------------------------|-------------------------------------|---------|
-| Shared C [core library] | [src/core](src/core)                | 1.6     |
-| C++                     | [src/cpp](src/cpp)                  | 1.6     |
-| Ruby                    | [src/ruby](src/ruby)                | 1.6     |
-| Python                  | [src/python](src/python)            | 1.6     |
-| PHP                     | [src/php](src/php)                  | 1.6     |
-| C#                      | [src/csharp](src/csharp)            | 1.6     |
-| Objective-C             | [src/objective-c](src/objective-c)  | 1.6     |
+| Shared C [core library] | [src/core](src/core)                | 1.8     |
+| C++                     | [src/cpp](src/cpp)                  | 1.8     |
+| Ruby                    | [src/ruby](src/ruby)                | 1.8     |
+| Python                  | [src/python](src/python)            | 1.8     |
+| PHP                     | [src/php](src/php)                  | 1.8     |
+| C#                      | [src/csharp](src/csharp)            | 1.8     |
+| Objective-C             | [src/objective-c](src/objective-c)  | 1.8     |
 
 Java source code is in the [grpc-java](http://github.com/grpc/grpc-java)
 repository. Go source code is in the
diff --git a/binding.gyp b/binding.gyp
deleted file mode 100644
index cb0a2fb..0000000
--- a/binding.gyp
+++ /dev/null
@@ -1,994 +0,0 @@
-# GRPC Node gyp file
-# This currently builds the Node extension and dependencies
-# This file has been automatically generated from a template file.
-# Please look at the templates directory instead.
-# This file can be regenerated from the template by running
-# tools/buildgen/generate_projects.sh
-
-# Copyright 2015 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.
-
-# Some of this file is built with the help of
-# https://n8.io/converting-a-c-library-to-gyp/
-{
-  'variables': {
-    'runtime%': 'node',
-    # Some Node installations use the system installation of OpenSSL, and on
-    # some systems, the system OpenSSL still does not have ALPN support. This
-    # will let users recompile gRPC to work without ALPN.
-    'grpc_alpn%': 'true',
-    # Indicates that the library should be built with gcov.
-    'grpc_gcov%': 'false',
-    # Indicates that the library should be built with compatibility for musl
-    # libc, so that it can run on Alpine Linux. This is only necessary if not
-    # building on Alpine Linux
-    'grpc_alpine%': 'false'
-  },
-  'target_defaults': {
-    'configurations': {
-      'Release': {
-        'cflags': [
-            '-O2',
-        ],
-        'defines': [
-            'NDEBUG',
-        ],
-      },
-      'Debug': {
-        'cflags': [
-            '-O0',
-        ],
-        'defines': [
-            '_DEBUG',
-            'DEBUG',
-        ],
-      },
-    },
-    'cflags': [
-        '-g',
-        '-Wall',
-        '-Wextra',
-        '-Werror',
-        '-Wno-long-long',
-        '-Wno-unused-parameter',
-        '-DOSATOMIC_USE_INLINED=1',
-    ],
-    'ldflags': [
-        '-g',
-    ],
-    'cflags_c': [
-      '-Werror',
-      '-std=c99'
-    ],
-    'cflags_cc': [
-      '-Werror',
-      '-std=c++11'
-    ],
-    'include_dirs': [
-      '.',
-      'include'
-    ],
-    'defines': [
-      'GPR_BACKWARDS_COMPATIBILITY_MODE',
-      'GRPC_ARES=0',
-      'GRPC_UV'
-    ],
-    'conditions': [
-      ['grpc_gcov=="true"', {
-        'cflags': [
-            '-O0',
-            '-fprofile-arcs',
-            '-ftest-coverage',
-            '-Wno-return-type',
-        ],
-        'defines': [
-            '_DEBUG',
-            'DEBUG',
-            'GPR_GCOV',
-        ],
-        'ldflags': [
-            '-fprofile-arcs',
-            '-ftest-coverage',
-            '-rdynamic',
-        ],
-      }],
-      ['grpc_alpine=="true"', {
-        'defines': [
-          'GPR_MUSL_LIBC_COMPAT'
-        ]
-      }],
-      ['OS!="win" and runtime=="electron"', {
-        "defines": [
-          'OPENSSL_NO_THREADS'
-        ]
-      }],
-      # This is the condition for using boringssl
-      ['OS=="win" or runtime=="electron"', {
-        "include_dirs": [
-          "third_party/boringssl/include"
-        ],
-        "defines": [
-          'OPENSSL_NO_ASM'
-        ]
-      }, {
-        'conditions': [
-          ["target_arch=='ia32'", {
-             "include_dirs": [ "<(node_root_dir)/deps/openssl/config/piii" ]
-          }],
-          ["target_arch=='x64'", {
-             "include_dirs": [ "<(node_root_dir)/deps/openssl/config/k8" ]
-          }],
-          ["target_arch=='arm'", {
-             "include_dirs": [ "<(node_root_dir)/deps/openssl/config/arm" ]
-          }],
-          ['grpc_alpn=="true"', {
-            'defines': [
-              'TSI_OPENSSL_ALPN_SUPPORT=1'
-            ],
-          }, {
-            'defines': [
-              'TSI_OPENSSL_ALPN_SUPPORT=0'
-            ],
-          }]
-        ],
-        'include_dirs': [
-          '<(node_root_dir)/deps/openssl/openssl/include',
-        ]
-      }],
-      ['OS == "win"', {
-        "include_dirs": [
-          "third_party/zlib",
-          "third_party/cares/cares"
-        ],
-        "defines": [
-          '_WIN32_WINNT=0x0600',
-          'WIN32_LEAN_AND_MEAN',
-          '_HAS_EXCEPTIONS=0',
-          'UNICODE',
-          '_UNICODE',
-          'NOMINMAX',
-        ],
-        "msvs_settings": {
-          'VCCLCompilerTool': {
-            'RuntimeLibrary': 1, # static debug
-          }
-        },
-        "libraries": [
-          "ws2_32"
-        ]
-      }, { # OS != "win"
-        'include_dirs': [
-          '<(node_root_dir)/deps/zlib',
-          '<(node_root_dir)/deps/cares/include'
-        ]
-      }],
-      ['OS == "mac"', {
-        'xcode_settings': {
-          'OTHER_CFLAGS': [
-              '-g',
-              '-Wall',
-              '-Wextra',
-              '-Werror',
-              '-Wno-long-long',
-              '-Wno-unused-parameter',
-              '-DOSATOMIC_USE_INLINED=1',
-          ],
-          'OTHER_CPLUSPLUSFLAGS': [
-              '-g',
-              '-Wall',
-              '-Wextra',
-              '-Werror',
-              '-Wno-long-long',
-              '-Wno-unused-parameter',
-              '-DOSATOMIC_USE_INLINED=1',
-            '-stdlib=libc++',
-            '-std=c++11',
-            '-Wno-error=deprecated-declarations'
-          ],
-        },
-      }]
-    ]
-  },
-  'conditions': [
-    ['OS=="win" or runtime=="electron"', {
-      'targets': [
-        {
-          'target_name': 'boringssl',
-          'product_prefix': 'lib',
-          'type': 'static_library',
-          'dependencies': [
-          ],
-          'sources': [
-            'src/boringssl/err_data.c',
-            'third_party/boringssl/crypto/aes/aes.c',
-            'third_party/boringssl/crypto/aes/key_wrap.c',
-            'third_party/boringssl/crypto/aes/mode_wrappers.c',
-            'third_party/boringssl/crypto/asn1/a_bitstr.c',
-            'third_party/boringssl/crypto/asn1/a_bool.c',
-            'third_party/boringssl/crypto/asn1/a_d2i_fp.c',
-            'third_party/boringssl/crypto/asn1/a_dup.c',
-            'third_party/boringssl/crypto/asn1/a_enum.c',
-            'third_party/boringssl/crypto/asn1/a_gentm.c',
-            'third_party/boringssl/crypto/asn1/a_i2d_fp.c',
-            'third_party/boringssl/crypto/asn1/a_int.c',
-            'third_party/boringssl/crypto/asn1/a_mbstr.c',
-            'third_party/boringssl/crypto/asn1/a_object.c',
-            'third_party/boringssl/crypto/asn1/a_octet.c',
-            'third_party/boringssl/crypto/asn1/a_print.c',
-            'third_party/boringssl/crypto/asn1/a_strnid.c',
-            'third_party/boringssl/crypto/asn1/a_time.c',
-            'third_party/boringssl/crypto/asn1/a_type.c',
-            'third_party/boringssl/crypto/asn1/a_utctm.c',
-            'third_party/boringssl/crypto/asn1/a_utf8.c',
-            'third_party/boringssl/crypto/asn1/asn1_lib.c',
-            'third_party/boringssl/crypto/asn1/asn1_par.c',
-            'third_party/boringssl/crypto/asn1/asn_pack.c',
-            'third_party/boringssl/crypto/asn1/f_enum.c',
-            'third_party/boringssl/crypto/asn1/f_int.c',
-            'third_party/boringssl/crypto/asn1/f_string.c',
-            'third_party/boringssl/crypto/asn1/t_bitst.c',
-            'third_party/boringssl/crypto/asn1/tasn_dec.c',
-            'third_party/boringssl/crypto/asn1/tasn_enc.c',
-            'third_party/boringssl/crypto/asn1/tasn_fre.c',
-            'third_party/boringssl/crypto/asn1/tasn_new.c',
-            'third_party/boringssl/crypto/asn1/tasn_typ.c',
-            'third_party/boringssl/crypto/asn1/tasn_utl.c',
-            'third_party/boringssl/crypto/asn1/time_support.c',
-            'third_party/boringssl/crypto/asn1/x_bignum.c',
-            'third_party/boringssl/crypto/asn1/x_long.c',
-            'third_party/boringssl/crypto/base64/base64.c',
-            'third_party/boringssl/crypto/bio/bio.c',
-            'third_party/boringssl/crypto/bio/bio_mem.c',
-            'third_party/boringssl/crypto/bio/connect.c',
-            'third_party/boringssl/crypto/bio/fd.c',
-            'third_party/boringssl/crypto/bio/file.c',
-            'third_party/boringssl/crypto/bio/hexdump.c',
-            'third_party/boringssl/crypto/bio/pair.c',
-            'third_party/boringssl/crypto/bio/printf.c',
-            'third_party/boringssl/crypto/bio/socket.c',
-            'third_party/boringssl/crypto/bio/socket_helper.c',
-            'third_party/boringssl/crypto/bn/add.c',
-            'third_party/boringssl/crypto/bn/asm/x86_64-gcc.c',
-            'third_party/boringssl/crypto/bn/bn.c',
-            'third_party/boringssl/crypto/bn/bn_asn1.c',
-            'third_party/boringssl/crypto/bn/cmp.c',
-            'third_party/boringssl/crypto/bn/convert.c',
-            'third_party/boringssl/crypto/bn/ctx.c',
-            'third_party/boringssl/crypto/bn/div.c',
-            'third_party/boringssl/crypto/bn/exponentiation.c',
-            'third_party/boringssl/crypto/bn/gcd.c',
-            'third_party/boringssl/crypto/bn/generic.c',
-            'third_party/boringssl/crypto/bn/kronecker.c',
-            'third_party/boringssl/crypto/bn/montgomery.c',
-            'third_party/boringssl/crypto/bn/montgomery_inv.c',
-            'third_party/boringssl/crypto/bn/mul.c',
-            'third_party/boringssl/crypto/bn/prime.c',
-            'third_party/boringssl/crypto/bn/random.c',
-            'third_party/boringssl/crypto/bn/rsaz_exp.c',
-            'third_party/boringssl/crypto/bn/shift.c',
-            'third_party/boringssl/crypto/bn/sqrt.c',
-            'third_party/boringssl/crypto/buf/buf.c',
-            'third_party/boringssl/crypto/bytestring/asn1_compat.c',
-            'third_party/boringssl/crypto/bytestring/ber.c',
-            'third_party/boringssl/crypto/bytestring/cbb.c',
-            'third_party/boringssl/crypto/bytestring/cbs.c',
-            'third_party/boringssl/crypto/chacha/chacha.c',
-            'third_party/boringssl/crypto/cipher/aead.c',
-            'third_party/boringssl/crypto/cipher/cipher.c',
-            'third_party/boringssl/crypto/cipher/derive_key.c',
-            'third_party/boringssl/crypto/cipher/e_aes.c',
-            'third_party/boringssl/crypto/cipher/e_chacha20poly1305.c',
-            'third_party/boringssl/crypto/cipher/e_des.c',
-            'third_party/boringssl/crypto/cipher/e_null.c',
-            'third_party/boringssl/crypto/cipher/e_rc2.c',
-            'third_party/boringssl/crypto/cipher/e_rc4.c',
-            'third_party/boringssl/crypto/cipher/e_ssl3.c',
-            'third_party/boringssl/crypto/cipher/e_tls.c',
-            'third_party/boringssl/crypto/cipher/tls_cbc.c',
-            'third_party/boringssl/crypto/cmac/cmac.c',
-            'third_party/boringssl/crypto/conf/conf.c',
-            'third_party/boringssl/crypto/cpu-aarch64-linux.c',
-            'third_party/boringssl/crypto/cpu-arm-linux.c',
-            'third_party/boringssl/crypto/cpu-arm.c',
-            'third_party/boringssl/crypto/cpu-intel.c',
-            'third_party/boringssl/crypto/cpu-ppc64le.c',
-            'third_party/boringssl/crypto/crypto.c',
-            'third_party/boringssl/crypto/curve25519/curve25519.c',
-            'third_party/boringssl/crypto/curve25519/spake25519.c',
-            'third_party/boringssl/crypto/curve25519/x25519-x86_64.c',
-            'third_party/boringssl/crypto/des/des.c',
-            'third_party/boringssl/crypto/dh/check.c',
-            'third_party/boringssl/crypto/dh/dh.c',
-            'third_party/boringssl/crypto/dh/dh_asn1.c',
-            'third_party/boringssl/crypto/dh/params.c',
-            'third_party/boringssl/crypto/digest/digest.c',
-            'third_party/boringssl/crypto/digest/digests.c',
-            'third_party/boringssl/crypto/dsa/dsa.c',
-            'third_party/boringssl/crypto/dsa/dsa_asn1.c',
-            'third_party/boringssl/crypto/ec/ec.c',
-            'third_party/boringssl/crypto/ec/ec_asn1.c',
-            'third_party/boringssl/crypto/ec/ec_key.c',
-            'third_party/boringssl/crypto/ec/ec_montgomery.c',
-            'third_party/boringssl/crypto/ec/oct.c',
-            'third_party/boringssl/crypto/ec/p224-64.c',
-            'third_party/boringssl/crypto/ec/p256-64.c',
-            'third_party/boringssl/crypto/ec/p256-x86_64.c',
-            'third_party/boringssl/crypto/ec/simple.c',
-            'third_party/boringssl/crypto/ec/util-64.c',
-            'third_party/boringssl/crypto/ec/wnaf.c',
-            'third_party/boringssl/crypto/ecdh/ecdh.c',
-            'third_party/boringssl/crypto/ecdsa/ecdsa.c',
-            'third_party/boringssl/crypto/ecdsa/ecdsa_asn1.c',
-            'third_party/boringssl/crypto/engine/engine.c',
-            'third_party/boringssl/crypto/err/err.c',
-            'third_party/boringssl/crypto/evp/digestsign.c',
-            'third_party/boringssl/crypto/evp/evp.c',
-            'third_party/boringssl/crypto/evp/evp_asn1.c',
-            'third_party/boringssl/crypto/evp/evp_ctx.c',
-            'third_party/boringssl/crypto/evp/p_dsa_asn1.c',
-            'third_party/boringssl/crypto/evp/p_ec.c',
-            'third_party/boringssl/crypto/evp/p_ec_asn1.c',
-            'third_party/boringssl/crypto/evp/p_rsa.c',
-            'third_party/boringssl/crypto/evp/p_rsa_asn1.c',
-            'third_party/boringssl/crypto/evp/pbkdf.c',
-            'third_party/boringssl/crypto/evp/print.c',
-            'third_party/boringssl/crypto/evp/sign.c',
-            'third_party/boringssl/crypto/ex_data.c',
-            'third_party/boringssl/crypto/hkdf/hkdf.c',
-            'third_party/boringssl/crypto/hmac/hmac.c',
-            'third_party/boringssl/crypto/lhash/lhash.c',
-            'third_party/boringssl/crypto/md4/md4.c',
-            'third_party/boringssl/crypto/md5/md5.c',
-            'third_party/boringssl/crypto/mem.c',
-            'third_party/boringssl/crypto/modes/cbc.c',
-            'third_party/boringssl/crypto/modes/cfb.c',
-            'third_party/boringssl/crypto/modes/ctr.c',
-            'third_party/boringssl/crypto/modes/gcm.c',
-            'third_party/boringssl/crypto/modes/ofb.c',
-            'third_party/boringssl/crypto/modes/polyval.c',
-            'third_party/boringssl/crypto/obj/obj.c',
-            'third_party/boringssl/crypto/obj/obj_xref.c',
-            'third_party/boringssl/crypto/pem/pem_all.c',
-            'third_party/boringssl/crypto/pem/pem_info.c',
-            'third_party/boringssl/crypto/pem/pem_lib.c',
-            'third_party/boringssl/crypto/pem/pem_oth.c',
-            'third_party/boringssl/crypto/pem/pem_pk8.c',
-            'third_party/boringssl/crypto/pem/pem_pkey.c',
-            'third_party/boringssl/crypto/pem/pem_x509.c',
-            'third_party/boringssl/crypto/pem/pem_xaux.c',
-            'third_party/boringssl/crypto/pkcs8/p5_pbev2.c',
-            'third_party/boringssl/crypto/pkcs8/p8_pkey.c',
-            'third_party/boringssl/crypto/pkcs8/pkcs8.c',
-            'third_party/boringssl/crypto/poly1305/poly1305.c',
-            'third_party/boringssl/crypto/poly1305/poly1305_arm.c',
-            'third_party/boringssl/crypto/poly1305/poly1305_vec.c',
-            'third_party/boringssl/crypto/pool/pool.c',
-            'third_party/boringssl/crypto/rand/deterministic.c',
-            'third_party/boringssl/crypto/rand/fuchsia.c',
-            'third_party/boringssl/crypto/rand/rand.c',
-            'third_party/boringssl/crypto/rand/urandom.c',
-            'third_party/boringssl/crypto/rand/windows.c',
-            'third_party/boringssl/crypto/rc4/rc4.c',
-            'third_party/boringssl/crypto/refcount_c11.c',
-            'third_party/boringssl/crypto/refcount_lock.c',
-            'third_party/boringssl/crypto/rsa/blinding.c',
-            'third_party/boringssl/crypto/rsa/padding.c',
-            'third_party/boringssl/crypto/rsa/rsa.c',
-            'third_party/boringssl/crypto/rsa/rsa_asn1.c',
-            'third_party/boringssl/crypto/rsa/rsa_impl.c',
-            'third_party/boringssl/crypto/sha/sha1-altivec.c',
-            'third_party/boringssl/crypto/sha/sha1.c',
-            'third_party/boringssl/crypto/sha/sha256.c',
-            'third_party/boringssl/crypto/sha/sha512.c',
-            'third_party/boringssl/crypto/stack/stack.c',
-            'third_party/boringssl/crypto/thread.c',
-            'third_party/boringssl/crypto/thread_none.c',
-            'third_party/boringssl/crypto/thread_pthread.c',
-            'third_party/boringssl/crypto/thread_win.c',
-            'third_party/boringssl/crypto/x509/a_digest.c',
-            'third_party/boringssl/crypto/x509/a_sign.c',
-            'third_party/boringssl/crypto/x509/a_strex.c',
-            'third_party/boringssl/crypto/x509/a_verify.c',
-            'third_party/boringssl/crypto/x509/algorithm.c',
-            'third_party/boringssl/crypto/x509/asn1_gen.c',
-            'third_party/boringssl/crypto/x509/by_dir.c',
-            'third_party/boringssl/crypto/x509/by_file.c',
-            'third_party/boringssl/crypto/x509/i2d_pr.c',
-            'third_party/boringssl/crypto/x509/pkcs7.c',
-            'third_party/boringssl/crypto/x509/rsa_pss.c',
-            'third_party/boringssl/crypto/x509/t_crl.c',
-            'third_party/boringssl/crypto/x509/t_req.c',
-            'third_party/boringssl/crypto/x509/t_x509.c',
-            'third_party/boringssl/crypto/x509/t_x509a.c',
-            'third_party/boringssl/crypto/x509/x509.c',
-            'third_party/boringssl/crypto/x509/x509_att.c',
-            'third_party/boringssl/crypto/x509/x509_cmp.c',
-            'third_party/boringssl/crypto/x509/x509_d2.c',
-            'third_party/boringssl/crypto/x509/x509_def.c',
-            'third_party/boringssl/crypto/x509/x509_ext.c',
-            'third_party/boringssl/crypto/x509/x509_lu.c',
-            'third_party/boringssl/crypto/x509/x509_obj.c',
-            'third_party/boringssl/crypto/x509/x509_r2x.c',
-            'third_party/boringssl/crypto/x509/x509_req.c',
-            'third_party/boringssl/crypto/x509/x509_set.c',
-            'third_party/boringssl/crypto/x509/x509_trs.c',
-            'third_party/boringssl/crypto/x509/x509_txt.c',
-            'third_party/boringssl/crypto/x509/x509_v3.c',
-            'third_party/boringssl/crypto/x509/x509_vfy.c',
-            'third_party/boringssl/crypto/x509/x509_vpm.c',
-            'third_party/boringssl/crypto/x509/x509cset.c',
-            'third_party/boringssl/crypto/x509/x509name.c',
-            'third_party/boringssl/crypto/x509/x509rset.c',
-            'third_party/boringssl/crypto/x509/x509spki.c',
-            'third_party/boringssl/crypto/x509/x509type.c',
-            'third_party/boringssl/crypto/x509/x_algor.c',
-            'third_party/boringssl/crypto/x509/x_all.c',
-            'third_party/boringssl/crypto/x509/x_attrib.c',
-            'third_party/boringssl/crypto/x509/x_crl.c',
-            'third_party/boringssl/crypto/x509/x_exten.c',
-            'third_party/boringssl/crypto/x509/x_info.c',
-            'third_party/boringssl/crypto/x509/x_name.c',
-            'third_party/boringssl/crypto/x509/x_pkey.c',
-            'third_party/boringssl/crypto/x509/x_pubkey.c',
-            'third_party/boringssl/crypto/x509/x_req.c',
-            'third_party/boringssl/crypto/x509/x_sig.c',
-            'third_party/boringssl/crypto/x509/x_spki.c',
-            'third_party/boringssl/crypto/x509/x_val.c',
-            'third_party/boringssl/crypto/x509/x_x509.c',
-            'third_party/boringssl/crypto/x509/x_x509a.c',
-            'third_party/boringssl/crypto/x509v3/pcy_cache.c',
-            'third_party/boringssl/crypto/x509v3/pcy_data.c',
-            'third_party/boringssl/crypto/x509v3/pcy_lib.c',
-            'third_party/boringssl/crypto/x509v3/pcy_map.c',
-            'third_party/boringssl/crypto/x509v3/pcy_node.c',
-            'third_party/boringssl/crypto/x509v3/pcy_tree.c',
-            'third_party/boringssl/crypto/x509v3/v3_akey.c',
-            'third_party/boringssl/crypto/x509v3/v3_akeya.c',
-            'third_party/boringssl/crypto/x509v3/v3_alt.c',
-            'third_party/boringssl/crypto/x509v3/v3_bcons.c',
-            'third_party/boringssl/crypto/x509v3/v3_bitst.c',
-            'third_party/boringssl/crypto/x509v3/v3_conf.c',
-            'third_party/boringssl/crypto/x509v3/v3_cpols.c',
-            'third_party/boringssl/crypto/x509v3/v3_crld.c',
-            'third_party/boringssl/crypto/x509v3/v3_enum.c',
-            'third_party/boringssl/crypto/x509v3/v3_extku.c',
-            'third_party/boringssl/crypto/x509v3/v3_genn.c',
-            'third_party/boringssl/crypto/x509v3/v3_ia5.c',
-            'third_party/boringssl/crypto/x509v3/v3_info.c',
-            'third_party/boringssl/crypto/x509v3/v3_int.c',
-            'third_party/boringssl/crypto/x509v3/v3_lib.c',
-            'third_party/boringssl/crypto/x509v3/v3_ncons.c',
-            'third_party/boringssl/crypto/x509v3/v3_pci.c',
-            'third_party/boringssl/crypto/x509v3/v3_pcia.c',
-            'third_party/boringssl/crypto/x509v3/v3_pcons.c',
-            'third_party/boringssl/crypto/x509v3/v3_pku.c',
-            'third_party/boringssl/crypto/x509v3/v3_pmaps.c',
-            'third_party/boringssl/crypto/x509v3/v3_prn.c',
-            'third_party/boringssl/crypto/x509v3/v3_purp.c',
-            'third_party/boringssl/crypto/x509v3/v3_skey.c',
-            'third_party/boringssl/crypto/x509v3/v3_sxnet.c',
-            'third_party/boringssl/crypto/x509v3/v3_utl.c',
-            'third_party/boringssl/ssl/bio_ssl.c',
-            'third_party/boringssl/ssl/custom_extensions.c',
-            'third_party/boringssl/ssl/d1_both.c',
-            'third_party/boringssl/ssl/d1_lib.c',
-            'third_party/boringssl/ssl/d1_pkt.c',
-            'third_party/boringssl/ssl/d1_srtp.c',
-            'third_party/boringssl/ssl/dtls_method.c',
-            'third_party/boringssl/ssl/dtls_record.c',
-            'third_party/boringssl/ssl/handshake_client.c',
-            'third_party/boringssl/ssl/handshake_server.c',
-            'third_party/boringssl/ssl/s3_both.c',
-            'third_party/boringssl/ssl/s3_lib.c',
-            'third_party/boringssl/ssl/s3_pkt.c',
-            'third_party/boringssl/ssl/ssl_aead_ctx.c',
-            'third_party/boringssl/ssl/ssl_asn1.c',
-            'third_party/boringssl/ssl/ssl_buffer.c',
-            'third_party/boringssl/ssl/ssl_cert.c',
-            'third_party/boringssl/ssl/ssl_cipher.c',
-            'third_party/boringssl/ssl/ssl_ecdh.c',
-            'third_party/boringssl/ssl/ssl_file.c',
-            'third_party/boringssl/ssl/ssl_lib.c',
-            'third_party/boringssl/ssl/ssl_privkey.c',
-            'third_party/boringssl/ssl/ssl_privkey_cc.cc',
-            'third_party/boringssl/ssl/ssl_session.c',
-            'third_party/boringssl/ssl/ssl_stat.c',
-            'third_party/boringssl/ssl/ssl_transcript.c',
-            'third_party/boringssl/ssl/ssl_x509.c',
-            'third_party/boringssl/ssl/t1_enc.c',
-            'third_party/boringssl/ssl/t1_lib.c',
-            'third_party/boringssl/ssl/tls13_both.c',
-            'third_party/boringssl/ssl/tls13_client.c',
-            'third_party/boringssl/ssl/tls13_enc.c',
-            'third_party/boringssl/ssl/tls13_server.c',
-            'third_party/boringssl/ssl/tls_method.c',
-            'third_party/boringssl/ssl/tls_record.c',
-          ],
-          'conditions': [
-            ['OS == "mac"', {
-              'xcode_settings': {
-                'MACOSX_DEPLOYMENT_TARGET': '10.9'
-              }
-            }]
-          ]
-        },
-      ],
-    }],
-    ['OS == "win" and runtime!="electron"', {
-      'targets': [
-        {
-          # IMPORTANT WINDOWS BUILD INFORMATION
-          # This library does not build on Windows without modifying the Node
-          # development packages that node-gyp downloads in order to build.
-          # Due to https://github.com/nodejs/node/issues/4932, the headers for
-          # BoringSSL conflict with the OpenSSL headers included by default
-          # when including the Node headers. The remedy for this is to remove
-          # the OpenSSL headers, from the downloaded Node development package,
-          # which is typically located in `.node-gyp` in your home directory.
-          #
-          # This is not true of Electron, which does not have OpenSSL headers.
-          'target_name': 'WINDOWS_BUILD_WARNING',
-          'rules': [
-            {
-              'rule_name': 'WINDOWS_BUILD_WARNING',
-              'extension': 'S',
-              'inputs': [
-                'package.json'
-              ],
-              'outputs': [
-                'ignore_this_part'
-              ],
-              'action': ['echo', 'IMPORTANT: Due to https://github.com/nodejs/node/issues/4932, to build this library on Windows, you must first remove <(node_root_dir)/include/node/openssl/']
-            }
-          ]
-        },
-      ]
-    }],
-    ['OS == "win"', {
-      'targets': [
-        # Only want to compile zlib under Windows
-        {
-          'target_name': 'z',
-          'product_prefix': 'lib',
-          'type': 'static_library',
-          'dependencies': [
-          ],
-          'sources': [
-            'third_party/zlib/adler32.c',
-            'third_party/zlib/compress.c',
-            'third_party/zlib/crc32.c',
-            'third_party/zlib/deflate.c',
-            'third_party/zlib/gzclose.c',
-            'third_party/zlib/gzlib.c',
-            'third_party/zlib/gzread.c',
-            'third_party/zlib/gzwrite.c',
-            'third_party/zlib/infback.c',
-            'third_party/zlib/inffast.c',
-            'third_party/zlib/inflate.c',
-            'third_party/zlib/inftrees.c',
-            'third_party/zlib/trees.c',
-            'third_party/zlib/uncompr.c',
-            'third_party/zlib/zutil.c',
-          ]
-        },
-      ]
-    }]
-  ],
-  'targets': [
-    {
-      'target_name': 'gpr',
-      'product_prefix': 'lib',
-      'type': 'static_library',
-      'dependencies': [
-      ],
-      'sources': [
-        'src/core/lib/profiling/basic_timers.c',
-        'src/core/lib/profiling/stap_timers.c',
-        'src/core/lib/support/alloc.c',
-        'src/core/lib/support/arena.c',
-        'src/core/lib/support/atm.c',
-        'src/core/lib/support/avl.c',
-        'src/core/lib/support/backoff.c',
-        'src/core/lib/support/cmdline.c',
-        'src/core/lib/support/cpu_iphone.c',
-        'src/core/lib/support/cpu_linux.c',
-        'src/core/lib/support/cpu_posix.c',
-        'src/core/lib/support/cpu_windows.c',
-        'src/core/lib/support/env_linux.c',
-        'src/core/lib/support/env_posix.c',
-        'src/core/lib/support/env_windows.c',
-        'src/core/lib/support/fork.c',
-        'src/core/lib/support/histogram.c',
-        'src/core/lib/support/host_port.c',
-        'src/core/lib/support/log.c',
-        'src/core/lib/support/log_android.c',
-        'src/core/lib/support/log_linux.c',
-        'src/core/lib/support/log_posix.c',
-        'src/core/lib/support/log_windows.c',
-        'src/core/lib/support/mpscq.c',
-        'src/core/lib/support/murmur_hash.c',
-        'src/core/lib/support/stack_lockfree.c',
-        'src/core/lib/support/string.c',
-        'src/core/lib/support/string_posix.c',
-        'src/core/lib/support/string_util_windows.c',
-        'src/core/lib/support/string_windows.c',
-        'src/core/lib/support/subprocess_posix.c',
-        'src/core/lib/support/subprocess_windows.c',
-        'src/core/lib/support/sync.c',
-        'src/core/lib/support/sync_posix.c',
-        'src/core/lib/support/sync_windows.c',
-        'src/core/lib/support/thd.c',
-        'src/core/lib/support/thd_posix.c',
-        'src/core/lib/support/thd_windows.c',
-        'src/core/lib/support/time.c',
-        'src/core/lib/support/time_posix.c',
-        'src/core/lib/support/time_precise.c',
-        'src/core/lib/support/time_windows.c',
-        'src/core/lib/support/tls_pthread.c',
-        'src/core/lib/support/tmpfile_msys.c',
-        'src/core/lib/support/tmpfile_posix.c',
-        'src/core/lib/support/tmpfile_windows.c',
-        'src/core/lib/support/wrap_memcpy.c',
-      ],
-      'conditions': [
-        ['OS == "mac"', {
-          'xcode_settings': {
-            'MACOSX_DEPLOYMENT_TARGET': '10.9'
-          }
-        }]
-      ]
-    },
-    {
-      'target_name': 'grpc',
-      'product_prefix': 'lib',
-      'type': 'static_library',
-      'dependencies': [
-        'gpr',
-      ],
-      'sources': [
-        'src/core/lib/surface/init.c',
-        'src/core/lib/channel/channel_args.c',
-        'src/core/lib/channel/channel_stack.c',
-        'src/core/lib/channel/channel_stack_builder.c',
-        'src/core/lib/channel/connected_channel.c',
-        'src/core/lib/channel/handshaker.c',
-        'src/core/lib/channel/handshaker_factory.c',
-        '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/compression/stream_compression_gzip.c',
-        'src/core/lib/compression/stream_compression_identity.c',
-        'src/core/lib/debug/stats.c',
-        'src/core/lib/debug/stats_data.c',
-        'src/core/lib/http/format_request.c',
-        'src/core/lib/http/httpcli.c',
-        'src/core/lib/http/parser.c',
-        'src/core/lib/iomgr/call_combiner.c',
-        'src/core/lib/iomgr/closure.c',
-        'src/core/lib/iomgr/combiner.c',
-        'src/core/lib/iomgr/endpoint.c',
-        'src/core/lib/iomgr/endpoint_pair_posix.c',
-        'src/core/lib/iomgr/endpoint_pair_uv.c',
-        'src/core/lib/iomgr/endpoint_pair_windows.c',
-        'src/core/lib/iomgr/error.c',
-        'src/core/lib/iomgr/ev_epoll1_linux.c',
-        'src/core/lib/iomgr/ev_epollex_linux.c',
-        'src/core/lib/iomgr/ev_epollsig_linux.c',
-        'src/core/lib/iomgr/ev_poll_posix.c',
-        'src/core/lib/iomgr/ev_posix.c',
-        'src/core/lib/iomgr/ev_windows.c',
-        'src/core/lib/iomgr/exec_ctx.c',
-        'src/core/lib/iomgr/executor.c',
-        'src/core/lib/iomgr/fork_posix.c',
-        'src/core/lib/iomgr/fork_windows.c',
-        'src/core/lib/iomgr/gethostname_fallback.c',
-        'src/core/lib/iomgr/gethostname_host_name_max.c',
-        'src/core/lib/iomgr/gethostname_sysconf.c',
-        'src/core/lib/iomgr/iocp_windows.c',
-        'src/core/lib/iomgr/iomgr.c',
-        'src/core/lib/iomgr/iomgr_posix.c',
-        'src/core/lib/iomgr/iomgr_uv.c',
-        'src/core/lib/iomgr/iomgr_windows.c',
-        'src/core/lib/iomgr/is_epollexclusive_available.c',
-        'src/core/lib/iomgr/load_file.c',
-        'src/core/lib/iomgr/lockfree_event.c',
-        'src/core/lib/iomgr/network_status_tracker.c',
-        'src/core/lib/iomgr/polling_entity.c',
-        'src/core/lib/iomgr/pollset_set_uv.c',
-        'src/core/lib/iomgr/pollset_set_windows.c',
-        'src/core/lib/iomgr/pollset_uv.c',
-        'src/core/lib/iomgr/pollset_windows.c',
-        'src/core/lib/iomgr/resolve_address_posix.c',
-        'src/core/lib/iomgr/resolve_address_uv.c',
-        'src/core/lib/iomgr/resolve_address_windows.c',
-        'src/core/lib/iomgr/resource_quota.c',
-        'src/core/lib/iomgr/sockaddr_utils.c',
-        'src/core/lib/iomgr/socket_factory_posix.c',
-        'src/core/lib/iomgr/socket_mutator.c',
-        'src/core/lib/iomgr/socket_utils_common_posix.c',
-        'src/core/lib/iomgr/socket_utils_linux.c',
-        'src/core/lib/iomgr/socket_utils_posix.c',
-        'src/core/lib/iomgr/socket_utils_uv.c',
-        'src/core/lib/iomgr/socket_utils_windows.c',
-        'src/core/lib/iomgr/socket_windows.c',
-        'src/core/lib/iomgr/tcp_client_posix.c',
-        'src/core/lib/iomgr/tcp_client_uv.c',
-        'src/core/lib/iomgr/tcp_client_windows.c',
-        'src/core/lib/iomgr/tcp_posix.c',
-        'src/core/lib/iomgr/tcp_server_posix.c',
-        'src/core/lib/iomgr/tcp_server_utils_posix_common.c',
-        'src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.c',
-        'src/core/lib/iomgr/tcp_server_utils_posix_noifaddrs.c',
-        'src/core/lib/iomgr/tcp_server_uv.c',
-        'src/core/lib/iomgr/tcp_server_windows.c',
-        'src/core/lib/iomgr/tcp_uv.c',
-        'src/core/lib/iomgr/tcp_windows.c',
-        'src/core/lib/iomgr/time_averaged_stats.c',
-        'src/core/lib/iomgr/timer_generic.c',
-        'src/core/lib/iomgr/timer_heap.c',
-        'src/core/lib/iomgr/timer_manager.c',
-        'src/core/lib/iomgr/timer_uv.c',
-        'src/core/lib/iomgr/udp_server.c',
-        'src/core/lib/iomgr/unix_sockets_posix.c',
-        'src/core/lib/iomgr/unix_sockets_posix_noop.c',
-        'src/core/lib/iomgr/wakeup_fd_cv.c',
-        'src/core/lib/iomgr/wakeup_fd_eventfd.c',
-        'src/core/lib/iomgr/wakeup_fd_nospecial.c',
-        'src/core/lib/iomgr/wakeup_fd_pipe.c',
-        'src/core/lib/iomgr/wakeup_fd_posix.c',
-        'src/core/lib/json/json.c',
-        'src/core/lib/json/json_reader.c',
-        'src/core/lib/json/json_string.c',
-        'src/core/lib/json/json_writer.c',
-        'src/core/lib/slice/b64.c',
-        'src/core/lib/slice/percent_encoding.c',
-        'src/core/lib/slice/slice.c',
-        'src/core/lib/slice/slice_buffer.c',
-        'src/core/lib/slice/slice_hash_table.c',
-        'src/core/lib/slice/slice_intern.c',
-        'src/core/lib/slice/slice_string_helpers.c',
-        'src/core/lib/surface/alarm.c',
-        'src/core/lib/surface/api_trace.c',
-        'src/core/lib/surface/byte_buffer.c',
-        'src/core/lib/surface/byte_buffer_reader.c',
-        'src/core/lib/surface/call.c',
-        'src/core/lib/surface/call_details.c',
-        'src/core/lib/surface/call_log_batch.c',
-        'src/core/lib/surface/channel.c',
-        'src/core/lib/surface/channel_init.c',
-        'src/core/lib/surface/channel_ping.c',
-        'src/core/lib/surface/channel_stack_type.c',
-        'src/core/lib/surface/completion_queue.c',
-        'src/core/lib/surface/completion_queue_factory.c',
-        'src/core/lib/surface/event_string.c',
-        'src/core/lib/surface/lame_client.cc',
-        'src/core/lib/surface/metadata_array.c',
-        'src/core/lib/surface/server.c',
-        'src/core/lib/surface/validate_metadata.c',
-        'src/core/lib/surface/version.c',
-        'src/core/lib/transport/bdp_estimator.c',
-        'src/core/lib/transport/byte_stream.c',
-        'src/core/lib/transport/connectivity_state.c',
-        'src/core/lib/transport/error_utils.c',
-        'src/core/lib/transport/metadata.c',
-        'src/core/lib/transport/metadata_batch.c',
-        'src/core/lib/transport/pid_controller.c',
-        'src/core/lib/transport/service_config.c',
-        'src/core/lib/transport/static_metadata.c',
-        'src/core/lib/transport/status_conversion.c',
-        'src/core/lib/transport/timeout_encoding.c',
-        'src/core/lib/transport/transport.c',
-        'src/core/lib/transport/transport_op_string.c',
-        'src/core/lib/debug/trace.c',
-        'src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c',
-        'src/core/ext/transport/chttp2/transport/bin_decoder.c',
-        'src/core/ext/transport/chttp2/transport/bin_encoder.c',
-        'src/core/ext/transport/chttp2/transport/chttp2_plugin.c',
-        'src/core/ext/transport/chttp2/transport/chttp2_transport.c',
-        'src/core/ext/transport/chttp2/transport/flow_control.c',
-        'src/core/ext/transport/chttp2/transport/frame_data.c',
-        'src/core/ext/transport/chttp2/transport/frame_goaway.c',
-        'src/core/ext/transport/chttp2/transport/frame_ping.c',
-        'src/core/ext/transport/chttp2/transport/frame_rst_stream.c',
-        'src/core/ext/transport/chttp2/transport/frame_settings.c',
-        'src/core/ext/transport/chttp2/transport/frame_window_update.c',
-        'src/core/ext/transport/chttp2/transport/hpack_encoder.c',
-        'src/core/ext/transport/chttp2/transport/hpack_parser.c',
-        'src/core/ext/transport/chttp2/transport/hpack_table.c',
-        'src/core/ext/transport/chttp2/transport/http2_settings.c',
-        'src/core/ext/transport/chttp2/transport/huffsyms.c',
-        'src/core/ext/transport/chttp2/transport/incoming_metadata.c',
-        'src/core/ext/transport/chttp2/transport/parsing.c',
-        'src/core/ext/transport/chttp2/transport/stream_lists.c',
-        'src/core/ext/transport/chttp2/transport/stream_map.c',
-        'src/core/ext/transport/chttp2/transport/varint.c',
-        'src/core/ext/transport/chttp2/transport/writing.c',
-        'src/core/ext/transport/chttp2/alpn/alpn.c',
-        'src/core/ext/filters/http/client/http_client_filter.c',
-        'src/core/ext/filters/http/http_filters_plugin.c',
-        'src/core/ext/filters/http/message_compress/message_compress_filter.c',
-        'src/core/ext/filters/http/server/http_server_filter.c',
-        'src/core/lib/http/httpcli_security_connector.c',
-        'src/core/lib/security/context/security_context.c',
-        'src/core/lib/security/credentials/composite/composite_credentials.c',
-        'src/core/lib/security/credentials/credentials.c',
-        'src/core/lib/security/credentials/credentials_metadata.c',
-        'src/core/lib/security/credentials/fake/fake_credentials.c',
-        'src/core/lib/security/credentials/google_default/credentials_generic.c',
-        'src/core/lib/security/credentials/google_default/google_default_credentials.c',
-        'src/core/lib/security/credentials/iam/iam_credentials.c',
-        'src/core/lib/security/credentials/jwt/json_token.c',
-        'src/core/lib/security/credentials/jwt/jwt_credentials.c',
-        'src/core/lib/security/credentials/jwt/jwt_verifier.c',
-        'src/core/lib/security/credentials/oauth2/oauth2_credentials.c',
-        'src/core/lib/security/credentials/plugin/plugin_credentials.c',
-        'src/core/lib/security/credentials/ssl/ssl_credentials.c',
-        'src/core/lib/security/transport/client_auth_filter.c',
-        'src/core/lib/security/transport/lb_targets_info.c',
-        'src/core/lib/security/transport/secure_endpoint.c',
-        'src/core/lib/security/transport/security_connector.c',
-        'src/core/lib/security/transport/security_handshaker.c',
-        'src/core/lib/security/transport/server_auth_filter.c',
-        'src/core/lib/security/transport/tsi_error.c',
-        'src/core/lib/security/util/json_util.c',
-        'src/core/lib/surface/init_secure.c',
-        'src/core/tsi/fake_transport_security.c',
-        'src/core/tsi/gts_transport_security.c',
-        'src/core/tsi/ssl_transport_security.c',
-        'src/core/tsi/transport_security_grpc.c',
-        'src/core/tsi/transport_security.c',
-        'src/core/tsi/transport_security_adapter.c',
-        'src/core/ext/transport/chttp2/server/chttp2_server.c',
-        'src/core/ext/transport/chttp2/client/secure/secure_channel_create.c',
-        'src/core/ext/filters/client_channel/channel_connectivity.c',
-        'src/core/ext/filters/client_channel/client_channel.c',
-        'src/core/ext/filters/client_channel/client_channel_factory.c',
-        'src/core/ext/filters/client_channel/client_channel_plugin.c',
-        'src/core/ext/filters/client_channel/connector.c',
-        'src/core/ext/filters/client_channel/http_connect_handshaker.c',
-        'src/core/ext/filters/client_channel/http_proxy.c',
-        'src/core/ext/filters/client_channel/lb_policy.c',
-        'src/core/ext/filters/client_channel/lb_policy_factory.c',
-        'src/core/ext/filters/client_channel/lb_policy_registry.c',
-        'src/core/ext/filters/client_channel/parse_address.c',
-        'src/core/ext/filters/client_channel/proxy_mapper.c',
-        'src/core/ext/filters/client_channel/proxy_mapper_registry.c',
-        'src/core/ext/filters/client_channel/resolver.c',
-        'src/core/ext/filters/client_channel/resolver_factory.c',
-        'src/core/ext/filters/client_channel/resolver_registry.c',
-        'src/core/ext/filters/client_channel/retry_throttle.c',
-        'src/core/ext/filters/client_channel/subchannel.c',
-        'src/core/ext/filters/client_channel/subchannel_index.c',
-        'src/core/ext/filters/client_channel/uri_parser.c',
-        'src/core/ext/filters/deadline/deadline_filter.c',
-        'src/core/ext/transport/chttp2/client/chttp2_connector.c',
-        'src/core/ext/transport/chttp2/server/insecure/server_chttp2.c',
-        'src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c',
-        'src/core/ext/transport/chttp2/client/insecure/channel_create.c',
-        'src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c',
-        'src/core/ext/transport/inproc/inproc_plugin.c',
-        'src/core/ext/transport/inproc/inproc_transport.c',
-        'src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.c',
-        'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.c',
-        'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.c',
-        'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.c',
-        'src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.c',
-        'src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c',
-        'third_party/nanopb/pb_common.c',
-        'third_party/nanopb/pb_decode.c',
-        'third_party/nanopb/pb_encode.c',
-        'src/core/ext/filters/client_channel/resolver/fake/fake_resolver.c',
-        'src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.c',
-        'src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.c',
-        'src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.c',
-        'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.c',
-        'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.c',
-        'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.c',
-        'src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.c',
-        'src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.c',
-        'src/core/ext/filters/load_reporting/server_load_reporting_filter.c',
-        'src/core/ext/filters/load_reporting/server_load_reporting_plugin.c',
-        'src/core/ext/census/base_resources.c',
-        'src/core/ext/census/context.c',
-        'src/core/ext/census/gen/census.pb.c',
-        'src/core/ext/census/gen/trace_context.pb.c',
-        'src/core/ext/census/grpc_context.c',
-        'src/core/ext/census/grpc_filter.c',
-        'src/core/ext/census/grpc_plugin.c',
-        'src/core/ext/census/initialize.c',
-        'src/core/ext/census/intrusive_hash_map.c',
-        'src/core/ext/census/mlog.c',
-        'src/core/ext/census/operation.c',
-        'src/core/ext/census/placeholders.c',
-        'src/core/ext/census/resource.c',
-        'src/core/ext/census/trace_context.c',
-        'src/core/ext/census/tracing.c',
-        'src/core/ext/filters/max_age/max_age_filter.c',
-        'src/core/ext/filters/message_size/message_size_filter.c',
-        'src/core/ext/filters/workarounds/workaround_cronet_compression_filter.c',
-        'src/core/ext/filters/workarounds/workaround_utils.c',
-        'src/core/plugin_registry/grpc_plugin_registry.c',
-      ],
-      'conditions': [
-        ['OS == "mac"', {
-          'xcode_settings': {
-            'MACOSX_DEPLOYMENT_TARGET': '10.9'
-          }
-        }]
-      ]
-    },
-    {
-      'include_dirs': [
-        "<!(node -e \"require('nan')\")"
-      ],
-      'cflags': [
-        '-pthread',
-        '-zdefs',
-        '-Wno-error=deprecated-declarations'
-      ],
-      "conditions": [
-        ['OS=="win" or runtime=="electron"', {
-          'dependencies': [
-            "boringssl",
-          ]
-        }],
-        ['OS=="win"', {
-          'dependencies': [
-            "z",
-          ]
-        }],
-        ['OS=="linux"', {
-          'ldflags': [
-            '-Wl,-wrap,memcpy'
-          ]
-        }],
-        ['OS == "mac"', {
-          'xcode_settings': {
-            'MACOSX_DEPLOYMENT_TARGET': '10.9'
-          }
-        }]
-      ],
-      "target_name": "grpc_node",
-      "sources": [
-        "src/node/ext/byte_buffer.cc",
-        "src/node/ext/call.cc",
-        "src/node/ext/call_credentials.cc",
-        "src/node/ext/channel.cc",
-        "src/node/ext/channel_credentials.cc",
-        "src/node/ext/completion_queue.cc",
-        "src/node/ext/node_grpc.cc",
-        "src/node/ext/server.cc",
-        "src/node/ext/server_credentials.cc",
-        "src/node/ext/slice.cc",
-        "src/node/ext/timeval.cc",
-      ],
-      "dependencies": [
-        "grpc",
-        "gpr",
-      ]
-    },
-    {
-      "target_name": "action_after_build",
-      "type": "none",
-      "dependencies": [ "<(module_name)" ],
-      "copies": [
-        {
-          "files": [ "<(PRODUCT_DIR)/<(module_name).node"],
-          "destination": "<(module_path)"
-        }
-      ]
-    }
-  ]
-}
diff --git a/build.yaml b/build.yaml
index 8723af6..aa614b8 100644
--- a/build.yaml
+++ b/build.yaml
@@ -12,9 +12,9 @@
   '#08': Use "-preN" suffixes to identify pre-release versions
   '#09': Per-language overrides are possible with (eg) ruby_version tag here
   '#10': See the expand_version.py for all the quirks here
-  core_version: 5.0.0-pre2
+  core_version: 5.0.0
   g_stands_for: generous
-  version: 1.8.0-pre2
+  version: 1.8.2
 filegroups:
 - name: census
   public_headers:
diff --git a/examples/python/interceptors/default_value/default_value_client_interceptor.py b/examples/python/interceptors/default_value/default_value_client_interceptor.py
new file mode 100644
index 0000000..c549f2b
--- /dev/null
+++ b/examples/python/interceptors/default_value/default_value_client_interceptor.py
@@ -0,0 +1,68 @@
+# 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.
+"""Interceptor that adds headers to outgoing requests."""
+
+import collections
+
+import grpc
+
+
+class _ConcreteValue(grpc.Future):
+
+    def __init__(self, result):
+        self._result = result
+
+    def cancel(self):
+        return False
+
+    def cancelled(self):
+        return False
+
+    def running(self):
+        return False
+
+    def done(self):
+        return True
+
+    def result(self, timeout=None):
+        return self._result
+
+    def exception(self, timeout=None):
+        return None
+
+    def traceback(self, timeout=None):
+        return None
+
+    def add_done_callback(self, fn):
+        fn(self._result)
+
+
+class DefaultValueClientInterceptor(grpc.UnaryUnaryClientInterceptor,
+                                    grpc.StreamUnaryClientInterceptor):
+
+    def __init__(self, value):
+        self._default = _ConcreteValue(value)
+
+    def _intercept_call(self, continuation, client_call_details,
+                        request_or_iterator):
+        response = continuation(client_call_details, request_or_iterator)
+        return self._default if response.exception() else response
+
+    def intercept_unary_unary(self, continuation, client_call_details, request):
+        return self._intercept_call(continuation, client_call_details, request)
+
+    def intercept_stream_unary(self, continuation, client_call_details,
+                               request_iterator):
+        return self._intercept_call(continuation, client_call_details,
+                                    request_iterator)
diff --git a/examples/python/interceptors/default_value/greeter_client.py b/examples/python/interceptors/default_value/greeter_client.py
new file mode 100644
index 0000000..aba7571
--- /dev/null
+++ b/examples/python/interceptors/default_value/greeter_client.py
@@ -0,0 +1,38 @@
+# 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.
+"""The Python implementation of the gRPC helloworld.Greeter client."""
+
+from __future__ import print_function
+
+import grpc
+
+import helloworld_pb2
+import helloworld_pb2_grpc
+import default_value_client_interceptor
+
+
+def run():
+    default_value = helloworld_pb2.HelloReply(
+        message='Hello from your local interceptor!')
+    default_value_interceptor = default_value_client_interceptor.DefaultValueClientInterceptor(
+        default_value)
+    channel = grpc.insecure_channel('localhost:50051')
+    channel = grpc.intercept_channel(channel, default_value_interceptor)
+    stub = helloworld_pb2_grpc.GreeterStub(channel)
+    response = stub.SayHello(helloworld_pb2.HelloRequest(name='you'))
+    print("Greeter client received: " + response.message)
+
+
+if __name__ == '__main__':
+    run()
diff --git a/examples/python/interceptors/default_value/helloworld_pb2.py b/examples/python/interceptors/default_value/helloworld_pb2.py
new file mode 100644
index 0000000..e18ab9a
--- /dev/null
+++ b/examples/python/interceptors/default_value/helloworld_pb2.py
@@ -0,0 +1,134 @@
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: helloworld.proto
+
+import sys
+_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import message as _message
+from google.protobuf import reflection as _reflection
+from google.protobuf import symbol_database as _symbol_database
+from google.protobuf import descriptor_pb2
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+
+
+DESCRIPTOR = _descriptor.FileDescriptor(
+  name='helloworld.proto',
+  package='helloworld',
+  syntax='proto3',
+  serialized_pb=_b('\n\x10helloworld.proto\x12\nhelloworld\"\x1c\n\x0cHelloRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\"\x1d\n\nHelloReply\x12\x0f\n\x07message\x18\x01 \x01(\t2I\n\x07Greeter\x12>\n\x08SayHello\x12\x18.helloworld.HelloRequest\x1a\x16.helloworld.HelloReply\"\x00\x42\x36\n\x1bio.grpc.examples.helloworldB\x0fHelloWorldProtoP\x01\xa2\x02\x03HLWb\x06proto3')
+)
+
+
+
+
+_HELLOREQUEST = _descriptor.Descriptor(
+  name='HelloRequest',
+  full_name='helloworld.HelloRequest',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='name', full_name='helloworld.HelloRequest.name', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=_b("").decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=32,
+  serialized_end=60,
+)
+
+
+_HELLOREPLY = _descriptor.Descriptor(
+  name='HelloReply',
+  full_name='helloworld.HelloReply',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='message', full_name='helloworld.HelloReply.message', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=_b("").decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=62,
+  serialized_end=91,
+)
+
+DESCRIPTOR.message_types_by_name['HelloRequest'] = _HELLOREQUEST
+DESCRIPTOR.message_types_by_name['HelloReply'] = _HELLOREPLY
+_sym_db.RegisterFileDescriptor(DESCRIPTOR)
+
+HelloRequest = _reflection.GeneratedProtocolMessageType('HelloRequest', (_message.Message,), dict(
+  DESCRIPTOR = _HELLOREQUEST,
+  __module__ = 'helloworld_pb2'
+  # @@protoc_insertion_point(class_scope:helloworld.HelloRequest)
+  ))
+_sym_db.RegisterMessage(HelloRequest)
+
+HelloReply = _reflection.GeneratedProtocolMessageType('HelloReply', (_message.Message,), dict(
+  DESCRIPTOR = _HELLOREPLY,
+  __module__ = 'helloworld_pb2'
+  # @@protoc_insertion_point(class_scope:helloworld.HelloReply)
+  ))
+_sym_db.RegisterMessage(HelloReply)
+
+
+DESCRIPTOR.has_options = True
+DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), _b('\n\033io.grpc.examples.helloworldB\017HelloWorldProtoP\001\242\002\003HLW'))
+
+_GREETER = _descriptor.ServiceDescriptor(
+  name='Greeter',
+  full_name='helloworld.Greeter',
+  file=DESCRIPTOR,
+  index=0,
+  options=None,
+  serialized_start=93,
+  serialized_end=166,
+  methods=[
+  _descriptor.MethodDescriptor(
+    name='SayHello',
+    full_name='helloworld.Greeter.SayHello',
+    index=0,
+    containing_service=None,
+    input_type=_HELLOREQUEST,
+    output_type=_HELLOREPLY,
+    options=None,
+  ),
+])
+_sym_db.RegisterServiceDescriptor(_GREETER)
+
+DESCRIPTOR.services_by_name['Greeter'] = _GREETER
+
+# @@protoc_insertion_point(module_scope)
diff --git a/examples/python/interceptors/default_value/helloworld_pb2_grpc.py b/examples/python/interceptors/default_value/helloworld_pb2_grpc.py
new file mode 100644
index 0000000..18e07d1
--- /dev/null
+++ b/examples/python/interceptors/default_value/helloworld_pb2_grpc.py
@@ -0,0 +1,46 @@
+# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
+import grpc
+
+import helloworld_pb2 as helloworld__pb2
+
+
+class GreeterStub(object):
+  """The greeting service definition.
+  """
+
+  def __init__(self, channel):
+    """Constructor.
+
+    Args:
+      channel: A grpc.Channel.
+    """
+    self.SayHello = channel.unary_unary(
+        '/helloworld.Greeter/SayHello',
+        request_serializer=helloworld__pb2.HelloRequest.SerializeToString,
+        response_deserializer=helloworld__pb2.HelloReply.FromString,
+        )
+
+
+class GreeterServicer(object):
+  """The greeting service definition.
+  """
+
+  def SayHello(self, request, context):
+    """Sends a greeting
+    """
+    context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+    context.set_details('Method not implemented!')
+    raise NotImplementedError('Method not implemented!')
+
+
+def add_GreeterServicer_to_server(servicer, server):
+  rpc_method_handlers = {
+      'SayHello': grpc.unary_unary_rpc_method_handler(
+          servicer.SayHello,
+          request_deserializer=helloworld__pb2.HelloRequest.FromString,
+          response_serializer=helloworld__pb2.HelloReply.SerializeToString,
+      ),
+  }
+  generic_handler = grpc.method_handlers_generic_handler(
+      'helloworld.Greeter', rpc_method_handlers)
+  server.add_generic_rpc_handlers((generic_handler,))
diff --git a/examples/python/interceptors/headers/generic_client_interceptor.py b/examples/python/interceptors/headers/generic_client_interceptor.py
new file mode 100644
index 0000000..30b0755
--- /dev/null
+++ b/examples/python/interceptors/headers/generic_client_interceptor.py
@@ -0,0 +1,55 @@
+# 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.
+"""Base class for interceptors that operate on all RPC types."""
+
+import grpc
+
+
+class _GenericClientInterceptor(
+        grpc.UnaryUnaryClientInterceptor, grpc.UnaryStreamClientInterceptor,
+        grpc.StreamUnaryClientInterceptor, grpc.StreamStreamClientInterceptor):
+
+    def __init__(self, interceptor_function):
+        self._fn = interceptor_function
+
+    def intercept_unary_unary(self, continuation, client_call_details, request):
+        new_details, new_request_iterator, postprocess = self._fn(
+            client_call_details, iter((request,)), False, False)
+        response = continuation(new_details, next(new_request_iterator))
+        return postprocess(response) if postprocess else response
+
+    def intercept_unary_stream(self, continuation, client_call_details,
+                               request):
+        new_details, new_request_iterator, postprocess = self._fn(
+            client_call_details, iter((request,)), False, True)
+        response_it = continuation(new_details, new_request_iterator)
+        return postprocess(response_it) if postprocess else response_it
+
+    def intercept_stream_unary(self, continuation, client_call_details,
+                               request_iterator):
+        new_details, new_request_iterator, postprocess = self._fn(
+            client_call_details, request_iterator, True, False)
+        response = continuation(new_details, next(new_request_iterator))
+        return postprocess(response) if postprocess else response
+
+    def intercept_stream_stream(self, continuation, client_call_details,
+                                request_iterator):
+        new_details, new_request_iterator, postprocess = self._fn(
+            client_call_details, request_iterator, True, True)
+        response_it = continuation(new_details, new_request_iterator)
+        return postprocess(response_it) if postprocess else response_it
+
+
+def create(intercept_call):
+    return _GenericClientInterceptor(intercept_call)
diff --git a/examples/python/interceptors/headers/greeter_client.py b/examples/python/interceptors/headers/greeter_client.py
new file mode 100644
index 0000000..2b0dd3e
--- /dev/null
+++ b/examples/python/interceptors/headers/greeter_client.py
@@ -0,0 +1,36 @@
+# 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.
+"""The Python implementation of the GRPC helloworld.Greeter client."""
+
+from __future__ import print_function
+
+import grpc
+
+import helloworld_pb2
+import helloworld_pb2_grpc
+import header_manipulator_client_interceptor
+
+
+def run():
+    header_adder_interceptor = header_manipulator_client_interceptor.header_adder_interceptor(
+        'one-time-password', '42')
+    channel = grpc.insecure_channel('localhost:50051')
+    channel = grpc.intercept_channel(channel, header_adder_interceptor)
+    stub = helloworld_pb2_grpc.GreeterStub(channel)
+    response = stub.SayHello(helloworld_pb2.HelloRequest(name='you'))
+    print("Greeter client received: " + response.message)
+
+
+if __name__ == '__main__':
+    run()
diff --git a/examples/python/interceptors/headers/greeter_server.py b/examples/python/interceptors/headers/greeter_server.py
new file mode 100644
index 0000000..0196860
--- /dev/null
+++ b/examples/python/interceptors/headers/greeter_server.py
@@ -0,0 +1,52 @@
+# 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.
+"""The Python implementation of the GRPC helloworld.Greeter server."""
+
+from concurrent import futures
+import time
+
+import grpc
+
+import helloworld_pb2
+import helloworld_pb2_grpc
+from request_header_validator_interceptor import RequestHeaderValidatorInterceptor
+
+_ONE_DAY_IN_SECONDS = 60 * 60 * 24
+
+
+class Greeter(helloworld_pb2_grpc.GreeterServicer):
+
+    def SayHello(self, request, context):
+        return helloworld_pb2.HelloReply(message='Hello, %s!' % request.name)
+
+
+def serve():
+    header_validator = RequestHeaderValidatorInterceptor(
+        'one-time-password', '42', grpc.StatusCode.UNAUTHENTICATED,
+        'Access denied!')
+    server = grpc.server(
+        futures.ThreadPoolExecutor(max_workers=10),
+        interceptors=(header_validator,))
+    helloworld_pb2_grpc.add_GreeterServicer_to_server(Greeter(), server)
+    server.add_insecure_port('[::]:50051')
+    server.start()
+    try:
+        while True:
+            time.sleep(_ONE_DAY_IN_SECONDS)
+    except KeyboardInterrupt:
+        server.stop(0)
+
+
+if __name__ == '__main__':
+    serve()
diff --git a/examples/python/interceptors/headers/header_manipulator_client_interceptor.py b/examples/python/interceptors/headers/header_manipulator_client_interceptor.py
new file mode 100644
index 0000000..ac7c605
--- /dev/null
+++ b/examples/python/interceptors/headers/header_manipulator_client_interceptor.py
@@ -0,0 +1,42 @@
+# 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.
+"""Interceptor that adds headers to outgoing requests."""
+
+import collections
+
+import grpc
+import generic_client_interceptor
+
+
+class _ClientCallDetails(
+        collections.namedtuple('_ClientCallDetails',
+                               ('method', 'timeout', 'metadata',
+                                'credentials')), grpc.ClientCallDetails):
+    pass
+
+
+def header_adder_interceptor(header, value):
+
+    def intercept_call(client_call_details, request_iterator, request_streaming,
+                       response_streaming):
+        metadata = []
+        if client_call_details.metadata is not None:
+            metadata = list(client_call_details.metadata)
+        metadata.append((header, value,))
+        client_call_details = _ClientCallDetails(
+            client_call_details.method, client_call_details.timeout, metadata,
+            client_call_details.credentials)
+        return client_call_details, request_iterator, None
+
+    return generic_client_interceptor.create(intercept_call)
diff --git a/examples/python/interceptors/headers/helloworld_pb2.py b/examples/python/interceptors/headers/helloworld_pb2.py
new file mode 100644
index 0000000..e18ab9a
--- /dev/null
+++ b/examples/python/interceptors/headers/helloworld_pb2.py
@@ -0,0 +1,134 @@
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: helloworld.proto
+
+import sys
+_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import message as _message
+from google.protobuf import reflection as _reflection
+from google.protobuf import symbol_database as _symbol_database
+from google.protobuf import descriptor_pb2
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+
+
+DESCRIPTOR = _descriptor.FileDescriptor(
+  name='helloworld.proto',
+  package='helloworld',
+  syntax='proto3',
+  serialized_pb=_b('\n\x10helloworld.proto\x12\nhelloworld\"\x1c\n\x0cHelloRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\"\x1d\n\nHelloReply\x12\x0f\n\x07message\x18\x01 \x01(\t2I\n\x07Greeter\x12>\n\x08SayHello\x12\x18.helloworld.HelloRequest\x1a\x16.helloworld.HelloReply\"\x00\x42\x36\n\x1bio.grpc.examples.helloworldB\x0fHelloWorldProtoP\x01\xa2\x02\x03HLWb\x06proto3')
+)
+
+
+
+
+_HELLOREQUEST = _descriptor.Descriptor(
+  name='HelloRequest',
+  full_name='helloworld.HelloRequest',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='name', full_name='helloworld.HelloRequest.name', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=_b("").decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=32,
+  serialized_end=60,
+)
+
+
+_HELLOREPLY = _descriptor.Descriptor(
+  name='HelloReply',
+  full_name='helloworld.HelloReply',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='message', full_name='helloworld.HelloReply.message', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=_b("").decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=62,
+  serialized_end=91,
+)
+
+DESCRIPTOR.message_types_by_name['HelloRequest'] = _HELLOREQUEST
+DESCRIPTOR.message_types_by_name['HelloReply'] = _HELLOREPLY
+_sym_db.RegisterFileDescriptor(DESCRIPTOR)
+
+HelloRequest = _reflection.GeneratedProtocolMessageType('HelloRequest', (_message.Message,), dict(
+  DESCRIPTOR = _HELLOREQUEST,
+  __module__ = 'helloworld_pb2'
+  # @@protoc_insertion_point(class_scope:helloworld.HelloRequest)
+  ))
+_sym_db.RegisterMessage(HelloRequest)
+
+HelloReply = _reflection.GeneratedProtocolMessageType('HelloReply', (_message.Message,), dict(
+  DESCRIPTOR = _HELLOREPLY,
+  __module__ = 'helloworld_pb2'
+  # @@protoc_insertion_point(class_scope:helloworld.HelloReply)
+  ))
+_sym_db.RegisterMessage(HelloReply)
+
+
+DESCRIPTOR.has_options = True
+DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), _b('\n\033io.grpc.examples.helloworldB\017HelloWorldProtoP\001\242\002\003HLW'))
+
+_GREETER = _descriptor.ServiceDescriptor(
+  name='Greeter',
+  full_name='helloworld.Greeter',
+  file=DESCRIPTOR,
+  index=0,
+  options=None,
+  serialized_start=93,
+  serialized_end=166,
+  methods=[
+  _descriptor.MethodDescriptor(
+    name='SayHello',
+    full_name='helloworld.Greeter.SayHello',
+    index=0,
+    containing_service=None,
+    input_type=_HELLOREQUEST,
+    output_type=_HELLOREPLY,
+    options=None,
+  ),
+])
+_sym_db.RegisterServiceDescriptor(_GREETER)
+
+DESCRIPTOR.services_by_name['Greeter'] = _GREETER
+
+# @@protoc_insertion_point(module_scope)
diff --git a/examples/python/interceptors/headers/helloworld_pb2_grpc.py b/examples/python/interceptors/headers/helloworld_pb2_grpc.py
new file mode 100644
index 0000000..18e07d1
--- /dev/null
+++ b/examples/python/interceptors/headers/helloworld_pb2_grpc.py
@@ -0,0 +1,46 @@
+# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
+import grpc
+
+import helloworld_pb2 as helloworld__pb2
+
+
+class GreeterStub(object):
+  """The greeting service definition.
+  """
+
+  def __init__(self, channel):
+    """Constructor.
+
+    Args:
+      channel: A grpc.Channel.
+    """
+    self.SayHello = channel.unary_unary(
+        '/helloworld.Greeter/SayHello',
+        request_serializer=helloworld__pb2.HelloRequest.SerializeToString,
+        response_deserializer=helloworld__pb2.HelloReply.FromString,
+        )
+
+
+class GreeterServicer(object):
+  """The greeting service definition.
+  """
+
+  def SayHello(self, request, context):
+    """Sends a greeting
+    """
+    context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+    context.set_details('Method not implemented!')
+    raise NotImplementedError('Method not implemented!')
+
+
+def add_GreeterServicer_to_server(servicer, server):
+  rpc_method_handlers = {
+      'SayHello': grpc.unary_unary_rpc_method_handler(
+          servicer.SayHello,
+          request_deserializer=helloworld__pb2.HelloRequest.FromString,
+          response_serializer=helloworld__pb2.HelloReply.SerializeToString,
+      ),
+  }
+  generic_handler = grpc.method_handlers_generic_handler(
+      'helloworld.Greeter', rpc_method_handlers)
+  server.add_generic_rpc_handlers((generic_handler,))
diff --git a/examples/python/interceptors/headers/request_header_validator_interceptor.py b/examples/python/interceptors/headers/request_header_validator_interceptor.py
new file mode 100644
index 0000000..95af417
--- /dev/null
+++ b/examples/python/interceptors/headers/request_header_validator_interceptor.py
@@ -0,0 +1,39 @@
+# 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.
+"""Interceptor that ensures a specific header is present."""
+
+import grpc
+
+
+def _unary_unary_rpc_terminator(code, details):
+
+    def terminate(ignored_request, context):
+        context.abort(code, details)
+
+    return grpc.unary_unary_rpc_method_handler(terminate)
+
+
+class RequestHeaderValidatorInterceptor(grpc.ServerInterceptor):
+
+    def __init__(self, header, value, code, details):
+        self._header = header
+        self._value = value
+        self._terminator = _unary_unary_rpc_terminator(code, details)
+
+    def intercept_service(self, continuation, handler_call_details):
+        if (self._header,
+                self._value) in handler_call_details.invocation_metadata:
+            return continuation(handler_call_details)
+        else:
+            return self._terminator
diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec
index 83ad46f..57e08ec 100644
--- a/gRPC-Core.podspec
+++ b/gRPC-Core.podspec
@@ -22,7 +22,7 @@
 
 Pod::Spec.new do |s|
   s.name     = 'gRPC-Core'
-  version = '1.8.0-pre2'
+  version = '1.8.2'
   s.version  = version
   s.summary  = 'Core cross-platform gRPC library, written in C'
   s.homepage = 'https://grpc.io'
diff --git a/gRPC-ProtoRPC.podspec b/gRPC-ProtoRPC.podspec
index a73cd66..a09cb13 100644
--- a/gRPC-ProtoRPC.podspec
+++ b/gRPC-ProtoRPC.podspec
@@ -21,7 +21,7 @@
 
 Pod::Spec.new do |s|
   s.name     = 'gRPC-ProtoRPC'
-  version = '1.8.0-pre2'
+  version = '1.8.2'
   s.version  = version
   s.summary  = 'RPC library for Protocol Buffers, based on gRPC'
   s.homepage = 'https://grpc.io'
diff --git a/gRPC-RxLibrary.podspec b/gRPC-RxLibrary.podspec
index b788e4e..e567e7d 100644
--- a/gRPC-RxLibrary.podspec
+++ b/gRPC-RxLibrary.podspec
@@ -21,7 +21,7 @@
 
 Pod::Spec.new do |s|
   s.name     = 'gRPC-RxLibrary'
-  version = '1.8.0-pre2'
+  version = '1.8.2'
   s.version  = version
   s.summary  = 'Reactive Extensions library for iOS/OSX.'
   s.homepage = 'https://grpc.io'
diff --git a/gRPC.podspec b/gRPC.podspec
index 9adcb4d..033e0ce 100644
--- a/gRPC.podspec
+++ b/gRPC.podspec
@@ -20,7 +20,7 @@
 
 Pod::Spec.new do |s|
   s.name     = 'gRPC'
-  version = '1.8.0-pre2'
+  version = '1.8.2'
   s.version  = version
   s.summary  = 'gRPC client library for iOS/OSX'
   s.homepage = 'https://grpc.io'
diff --git a/package.json b/package.json
deleted file mode 100644
index 2b7930c..0000000
--- a/package.json
+++ /dev/null
@@ -1,103 +0,0 @@
-{
-  "name": "grpc",
-  "version": "1.7.2",
-  "author": "Google Inc.",
-  "description": "gRPC Library for Node",
-  "homepage": "https://grpc.io/",
-  "repository": {
-    "type": "git",
-    "url": "https://github.com/grpc/grpc.git"
-  },
-  "bugs": "https://github.com/grpc/grpc/issues",
-  "contributors": [
-    {
-      "name": "Michael Lumish",
-      "email": "mlumish@google.com"
-    }
-  ],
-  "directories": {
-    "lib": "src/node/src"
-  },
-  "scripts": {
-    "lint": "node ./node_modules/jshint/bin/jshint src/node/src src/node/test src/node/interop src/node/index.js --exclude-path=src/node/.jshintignore",
-    "test": "./node_modules/.bin/mocha src/node/test && npm run-script lint",
-    "electron-build": "./node_modules/.bin/node-pre-gyp configure build --runtime=electron --disturl=https://atom.io/download/atom-shell",
-    "gen_docs": "./node_modules/.bin/jsdoc -c src/node/jsdoc_conf.json",
-    "coverage": "./node_modules/.bin/istanbul cover ./node_modules/.bin/_mocha src/node/test",
-    "install": "./node_modules/.bin/node-pre-gyp install --fallback-to-build --library=static_library"
-  },
-  "bundledDependencies": [
-    "node-pre-gyp"
-  ],
-  "dependencies": {
-    "arguejs": "^0.2.3",
-    "lodash": "^4.15.0",
-    "nan": "^2.0.0",
-    "node-pre-gyp": "^0.6.35",
-    "protobufjs": "^5.0.0"
-  },
-  "devDependencies": {
-    "async": "^2.0.1",
-    "body-parser": "^1.15.2",
-    "electron-mocha": "^3.1.1",
-    "express": "^4.14.0",
-    "google-auth-library": "^0.9.2",
-    "google-protobuf": "^3.0.0",
-    "istanbul": "^0.4.4",
-    "jsdoc": "^3.3.2",
-    "jshint": "^2.5.0",
-    "minimist": "^1.1.0",
-    "mocha": "^3.0.2",
-    "mocha-jenkins-reporter": "^0.2.3",
-    "poisson-process": "^0.2.1"
-  },
-  "engines": {
-    "node": ">=4"
-  },
-  "binary": {
-    "module_name": "grpc_node",
-    "module_path": "src/node/extension_binary/{node_abi}-{platform}-{arch}",
-    "host": "https://storage.googleapis.com/",
-    "remote_path": "grpc-precompiled-binaries/node/{name}/v{version}",
-    "package_name": "{node_abi}-{platform}-{arch}.tar.gz"
-  },
-  "files": [
-    "LICENSE",
-    "src/node/README.md",
-    "src/proto",
-    "etc",
-    "src/node/index.js",
-    "src/node/src",
-    "src/node/ext",
-    "include/grpc",
-    "src/core",
-    "src/boringssl",
-    "src/zlib",
-    "third_party/nanopb",
-    "third_party/zlib",
-    "third_party/boringssl",
-    "binding.gyp"
-  ],
-  "main": "src/node/index.js",
-  "license": "Apache-2.0",
-  "jshintConfig": {
-    "bitwise": true,
-    "curly": true,
-    "eqeqeq": true,
-    "esnext": true,
-    "freeze": true,
-    "immed": true,
-    "indent": 2,
-    "latedef": "nofunc",
-    "maxlen": 80,
-    "mocha": true,
-    "newcap": true,
-    "node": true,
-    "noarg": true,
-    "quotmark": "single",
-    "strict": true,
-    "trailing": true,
-    "undef": true,
-    "unused": "vars"
-  }
-}
diff --git a/package.xml b/package.xml
index c1c8a87..eb0c8dc 100644
--- a/package.xml
+++ b/package.xml
@@ -13,8 +13,8 @@
  <date>2017-08-24</date>
  <time>16:06:07</time>
  <version>
-  <release>1.8.0RC2</release>
-  <api>1.8.0RC2</api>
+  <release>1.8.2</release>
+  <api>1.8.2</api>
  </version>
  <stability>
   <release>beta</release>
diff --git a/src/core/lib/iomgr/ev_poll_posix.cc b/src/core/lib/iomgr/ev_poll_posix.cc
index 8659559..13468b3 100644
--- a/src/core/lib/iomgr/ev_poll_posix.cc
+++ b/src/core/lib/iomgr/ev_poll_posix.cc
@@ -71,6 +71,7 @@
   int shutdown;
   int closed;
   int released;
+  gpr_atm pollhup;
   grpc_error* shutdown_error;
 
   /* The watcher list.
@@ -339,6 +340,7 @@
   r->on_done_closure = nullptr;
   r->closed = 0;
   r->released = 0;
+  gpr_atm_no_barrier_store(&r->pollhup, 0);
   r->read_notifier_pollset = nullptr;
 
   char* name2;
@@ -964,7 +966,8 @@
       pfds[0].events = POLLIN;
       pfds[0].revents = 0;
       for (i = 0; i < pollset->fd_count; i++) {
-        if (fd_is_orphaned(pollset->fds[i])) {
+        if (fd_is_orphaned(pollset->fds[i]) ||
+            gpr_atm_no_barrier_load(&pollset->fds[i]->pollhup) == 1) {
           GRPC_FD_UNREF(pollset->fds[i], "multipoller");
         } else {
           pollset->fds[fd_count++] = pollset->fds[i];
@@ -1031,6 +1034,12 @@
                       pfds[i].fd, (pfds[i].revents & POLLIN_CHECK) != 0,
                       (pfds[i].revents & POLLOUT_CHECK) != 0, pfds[i].revents);
             }
+            /* This is a mitigation to prevent poll() from spinning on a
+             ** POLLHUP https://github.com/grpc/grpc/pull/13665
+             */
+            if (pfds[i].revents & POLLHUP) {
+              gpr_atm_no_barrier_store(&watchers[i].fd->pollhup, 1);
+            }
             fd_end_poll(exec_ctx, &watchers[i], pfds[i].revents & POLLIN_CHECK,
                         pfds[i].revents & POLLOUT_CHECK, pollset);
           }
diff --git a/src/core/lib/iomgr/tcp_client_windows.cc b/src/core/lib/iomgr/tcp_client_windows.cc
index 103e6b7..8a87e92 100644
--- a/src/core/lib/iomgr/tcp_client_windows.cc
+++ b/src/core/lib/iomgr/tcp_client_windows.cc
@@ -104,6 +104,7 @@
       GPR_ASSERT(transfered_bytes == 0);
       if (!wsa_success) {
         error = GRPC_WSA_ERROR(WSAGetLastError(), "ConnectEx");
+        closesocket(socket->socket);
       } else {
         *ep =
             grpc_tcp_create(exec_ctx, socket, ac->channel_args, ac->addr_name);
diff --git a/src/core/lib/surface/version.cc b/src/core/lib/surface/version.cc
index a9cbe62..5e4f620 100644
--- a/src/core/lib/surface/version.cc
+++ b/src/core/lib/surface/version.cc
@@ -21,6 +21,6 @@
 
 #include <grpc/grpc.h>
 
-const char* grpc_version_string(void) { return "5.0.0-pre2"; }
+const char* grpc_version_string(void) { return "5.0.0"; }
 
 const char* grpc_g_stands_for(void) { return "generous"; }
diff --git a/src/cpp/common/version_cc.cc b/src/cpp/common/version_cc.cc
index 43c9ef6..26090b9 100644
--- a/src/cpp/common/version_cc.cc
+++ b/src/cpp/common/version_cc.cc
@@ -22,5 +22,5 @@
 #include <grpc++/grpc++.h>
 
 namespace grpc {
-grpc::string Version() { return "1.8.0-pre2"; }
+grpc::string Version() { return "1.8.2"; }
 }  // namespace grpc
diff --git a/src/csharp/Grpc.Core/Version.csproj.include b/src/csharp/Grpc.Core/Version.csproj.include
index 778f02d..662eb8f 100755
--- a/src/csharp/Grpc.Core/Version.csproj.include
+++ b/src/csharp/Grpc.Core/Version.csproj.include
@@ -1,7 +1,7 @@
 <!-- This file is generated -->
 <Project>
   <PropertyGroup>
-    <GrpcCsharpVersion>1.8.0-pre2</GrpcCsharpVersion>
+    <GrpcCsharpVersion>1.8.2</GrpcCsharpVersion>
     <GoogleProtobufVersion>3.3.0</GoogleProtobufVersion>
   </PropertyGroup>
 </Project>
diff --git a/src/csharp/Grpc.Core/VersionInfo.cs b/src/csharp/Grpc.Core/VersionInfo.cs
index da9ad8b..339e1a2 100644
--- a/src/csharp/Grpc.Core/VersionInfo.cs
+++ b/src/csharp/Grpc.Core/VersionInfo.cs
@@ -33,11 +33,11 @@
         /// <summary>
         /// Current <c>AssemblyFileVersion</c> of gRPC C# assemblies
         /// </summary>
-        public const string CurrentAssemblyFileVersion = "1.8.0.0";
+        public const string CurrentAssemblyFileVersion = "1.8.2.0";
 
         /// <summary>
         /// Current version of gRPC C#
         /// </summary>
-        public const string CurrentVersion = "1.8.0-pre2";
+        public const string CurrentVersion = "1.8.2";
     }
 }
diff --git a/src/csharp/build_packages_dotnetcli.bat b/src/csharp/build_packages_dotnetcli.bat
index 25b6036..19dfdaf 100755
--- a/src/csharp/build_packages_dotnetcli.bat
+++ b/src/csharp/build_packages_dotnetcli.bat
@@ -13,7 +13,7 @@
 @rem limitations under the License.
 
 @rem Current package versions
-set VERSION=1.8.0-pre2
+set VERSION=1.8.2
 
 @rem Adjust the location of nuget.exe
 set NUGET=C:\nuget\nuget.exe
diff --git a/src/csharp/build_packages_dotnetcli.sh b/src/csharp/build_packages_dotnetcli.sh
index a655f12..3ff66bc 100755
--- a/src/csharp/build_packages_dotnetcli.sh
+++ b/src/csharp/build_packages_dotnetcli.sh
@@ -39,7 +39,7 @@
 dotnet pack --configuration Release Grpc.HealthCheck --output ../../../artifacts
 dotnet pack --configuration Release Grpc.Reflection --output ../../../artifacts
 
-nuget pack Grpc.nuspec -Version "1.8.0-pre2" -OutputDirectory ../../artifacts
-nuget pack Grpc.Tools.nuspec -Version "1.8.0-pre2" -OutputDirectory ../../artifacts
+nuget pack Grpc.nuspec -Version "1.8.2" -OutputDirectory ../../artifacts
+nuget pack Grpc.Tools.nuspec -Version "1.8.2" -OutputDirectory ../../artifacts
 
 (cd ../../artifacts && zip csharp_nugets_dotnetcli.zip *.nupkg)
diff --git a/src/node/health_check/package.json b/src/node/health_check/package.json
deleted file mode 100644
index fca3a2a..0000000
--- a/src/node/health_check/package.json
+++ /dev/null
@@ -1,29 +0,0 @@
-{
-  "name": "grpc-health-check",
-  "version": "1.7.2",
-  "author": "Google Inc.",
-  "description": "Health check service for use with gRPC",
-  "repository": {
-    "type": "git",
-    "url": "https://github.com/grpc/grpc.git"
-  },
-  "bugs": "https://github.com/grpc/grpc/issues",
-  "contributors": [
-    {
-      "name": "Michael Lumish",
-      "email": "mlumish@google.com"
-    }
-  ],
-  "dependencies": {
-    "grpc": "^1.7.2",
-    "lodash": "^3.9.3",
-    "google-protobuf": "^3.0.0"
-  },
-  "files": [
-    "LICENSE",
-    "health.js",
-    "v1"
-  ],
-  "main": "src/node/index.js",
-  "license": "Apache-2.0"
-}
diff --git a/src/node/tools/package.json b/src/node/tools/package.json
deleted file mode 100644
index 99fd854..0000000
--- a/src/node/tools/package.json
+++ /dev/null
@@ -1,41 +0,0 @@
-{
-  "name": "grpc-tools",
-  "version": "1.7.2",
-  "author": "Google Inc.",
-  "description": "Tools for developing with gRPC on Node.js",
-  "homepage": "https://grpc.io/",
-  "repository": {
-    "type": "git",
-    "url": "https://github.com/grpc/grpc.git"
-  },
-  "bugs": "https://github.com/grpc/grpc/issues",
-  "contributors": [
-    {
-      "name": "Michael Lumish",
-      "email": "mlumish@google.com"
-    }
-  ],
-  "bin": {
-    "grpc_tools_node_protoc": "./bin/protoc.js",
-    "grpc_tools_node_protoc_plugin": "./bin/protoc_plugin.js"
-  },
-  "scripts": {
-    "install": "./node_modules/.bin/node-pre-gyp install"
-  },
-  "bundledDependencies": ["node-pre-gyp"],
-  "binary": {
-    "module_name": "grpc_tools",
-    "host": "https://storage.googleapis.com/",
-    "remote_path": "grpc-precompiled-binaries/node/{name}/v{version}",
-    "package_name": "{platform}-{arch}.tar.gz",
-    "module_path": "bin"
-  },
-  "files": [
-    "index.js",
-    "bin/protoc.js",
-    "bin/protoc_plugin.js",
-    "bin/google/protobuf",
-    "LICENSE"
-  ],
-  "main": "index.js"
-}
diff --git "a/src/objective-c/\041ProtoCompiler-gRPCPlugin.podspec" "b/src/objective-c/\041ProtoCompiler-gRPCPlugin.podspec"
index 4c3d656..148e031 100644
--- "a/src/objective-c/\041ProtoCompiler-gRPCPlugin.podspec"
+++ "b/src/objective-c/\041ProtoCompiler-gRPCPlugin.podspec"
@@ -42,7 +42,7 @@
   # exclamation mark ensures that other "regular" pods will be able to find it as it'll be installed
   # before them.
   s.name     = '!ProtoCompiler-gRPCPlugin'
-  v = '1.8.0-pre2'
+  v = '1.8.2'
   s.version  = v
   s.summary  = 'The gRPC ProtoC plugin generates Objective-C files from .proto services.'
   s.description = <<-DESC
diff --git a/src/objective-c/GRPCClient/private/version.h b/src/objective-c/GRPCClient/private/version.h
index 5854a7c..b8211a8 100644
--- a/src/objective-c/GRPCClient/private/version.h
+++ b/src/objective-c/GRPCClient/private/version.h
@@ -23,4 +23,4 @@
 // `tools/buildgen/generate_projects.sh`.
 
 
-#define GRPC_OBJC_VERSION_STRING @"1.8.0-pre2"
+#define GRPC_OBJC_VERSION_STRING @"1.8.2"
diff --git a/src/objective-c/tests/version.h b/src/objective-c/tests/version.h
index 31a9b64..170d888 100644
--- a/src/objective-c/tests/version.h
+++ b/src/objective-c/tests/version.h
@@ -23,5 +23,5 @@
 // `tools/buildgen/generate_projects.sh`.
 
 
-#define GRPC_OBJC_VERSION_STRING @"1.8.0-pre2"
-#define GRPC_C_VERSION_STRING @"5.0.0-pre2"
+#define GRPC_OBJC_VERSION_STRING @"1.8.2"
+#define GRPC_C_VERSION_STRING @"5.0.0"
diff --git a/src/php/composer.json b/src/php/composer.json
index 09471d2..e3047b2 100644
--- a/src/php/composer.json
+++ b/src/php/composer.json
@@ -2,7 +2,7 @@
   "name": "grpc/grpc-dev",
   "description": "gRPC library for PHP - for Developement use only",
   "license": "Apache-2.0",
-  "version": "1.8.0",
+  "version": "1.8.2",
   "require": {
     "php": ">=5.5.0",
     "google/protobuf": "^v3.3.0"
diff --git a/src/php/ext/grpc/version.h b/src/php/ext/grpc/version.h
index deb6977..277833b 100644
--- a/src/php/ext/grpc/version.h
+++ b/src/php/ext/grpc/version.h
@@ -20,6 +20,6 @@
 #ifndef VERSION_H
 #define VERSION_H
 
-#define PHP_GRPC_VERSION "1.8.0RC2"
+#define PHP_GRPC_VERSION "1.8.2"
 
 #endif /* VERSION_H */
diff --git a/src/python/grpcio/grpc/__init__.py b/src/python/grpcio/grpc/__init__.py
index 0f6bdfc..8b913ac 100644
--- a/src/python/grpcio/grpc/__init__.py
+++ b/src/python/grpcio/grpc/__init__.py
@@ -342,6 +342,170 @@
         raise NotImplementedError()
 
 
+##############  Invocation-Side Interceptor Interfaces & Classes  ##############
+
+
+class ClientCallDetails(six.with_metaclass(abc.ABCMeta)):
+    """Describes an RPC to be invoked.
+
+    This is an EXPERIMENTAL API.
+
+    Attributes:
+      method: The method name of the RPC.
+      timeout: An optional duration of time in seconds to allow for the RPC.
+      metadata: Optional :term:`metadata` to be transmitted to
+        the service-side of the RPC.
+      credentials: An optional CallCredentials for the RPC.
+    """
+
+
+class UnaryUnaryClientInterceptor(six.with_metaclass(abc.ABCMeta)):
+    """Affords intercepting unary-unary invocations.
+
+    This is an EXPERIMENTAL API.
+    """
+
+    @abc.abstractmethod
+    def intercept_unary_unary(self, continuation, client_call_details, request):
+        """Intercepts a unary-unary invocation asynchronously.
+
+        Args:
+          continuation: A function that proceeds with the invocation by
+            executing the next interceptor in chain or invoking the
+            actual RPC on the underlying Channel. It is the interceptor's
+            responsibility to call it if it decides to move the RPC forward.
+            The interceptor can use
+            `response_future = continuation(client_call_details, request)`
+            to continue with the RPC. `continuation` returns an object that is
+            both a Call for the RPC and a Future. In the event of RPC
+            completion, the return Call-Future's result value will be
+            the response message of the RPC. Should the event terminate
+            with non-OK status, the returned Call-Future's exception value
+            will be an RpcError.
+          client_call_details: A ClientCallDetails object describing the
+            outgoing RPC.
+          request: The request value for the RPC.
+
+        Returns:
+            An object that is both a Call for the RPC and a Future.
+            In the event of RPC completion, the return Call-Future's
+            result value will be the response message of the RPC.
+            Should the event terminate with non-OK status, the returned
+            Call-Future's exception value will be an RpcError.
+        """
+        raise NotImplementedError()
+
+
+class UnaryStreamClientInterceptor(six.with_metaclass(abc.ABCMeta)):
+    """Affords intercepting unary-stream invocations.
+
+    This is an EXPERIMENTAL API.
+    """
+
+    @abc.abstractmethod
+    def intercept_unary_stream(self, continuation, client_call_details,
+                               request):
+        """Intercepts a unary-stream invocation.
+
+        Args:
+          continuation: A function that proceeds with the invocation by
+            executing the next interceptor in chain or invoking the
+            actual RPC on the underlying Channel. It is the interceptor's
+            responsibility to call it if it decides to move the RPC forward.
+            The interceptor can use
+            `response_iterator = continuation(client_call_details, request)`
+            to continue with the RPC. `continuation` returns an object that is
+            both a Call for the RPC and an iterator for response values.
+            Drawing response values from the returned Call-iterator may
+            raise RpcError indicating termination of the RPC with non-OK
+            status.
+          client_call_details: A ClientCallDetails object describing the
+            outgoing RPC.
+          request: The request value for the RPC.
+
+        Returns:
+            An object that is both a Call for the RPC and an iterator of
+            response values. Drawing response values from the returned
+            Call-iterator may raise RpcError indicating termination of
+            the RPC with non-OK status.
+        """
+        raise NotImplementedError()
+
+
+class StreamUnaryClientInterceptor(six.with_metaclass(abc.ABCMeta)):
+    """Affords intercepting stream-unary invocations.
+
+    This is an EXPERIMENTAL API.
+    """
+
+    @abc.abstractmethod
+    def intercept_stream_unary(self, continuation, client_call_details,
+                               request_iterator):
+        """Intercepts a stream-unary invocation asynchronously.
+
+        Args:
+          continuation: A function that proceeds with the invocation by
+            executing the next interceptor in chain or invoking the
+            actual RPC on the underlying Channel. It is the interceptor's
+            responsibility to call it if it decides to move the RPC forward.
+            The interceptor can use
+            `response_future = continuation(client_call_details,
+                                            request_iterator)`
+            to continue with the RPC. `continuation` returns an object that is
+            both a Call for the RPC and a Future. In the event of RPC completion,
+            the return Call-Future's result value will be the response message
+            of the RPC. Should the event terminate with non-OK status, the
+            returned Call-Future's exception value will be an RpcError.
+          client_call_details: A ClientCallDetails object describing the
+            outgoing RPC.
+          request_iterator: An iterator that yields request values for the RPC.
+
+        Returns:
+            An object that is both a Call for the RPC and a Future.
+            In the event of RPC completion, the return Call-Future's
+            result value will be the response message of the RPC.
+            Should the event terminate with non-OK status, the returned
+            Call-Future's exception value will be an RpcError.
+        """
+        raise NotImplementedError()
+
+
+class StreamStreamClientInterceptor(six.with_metaclass(abc.ABCMeta)):
+    """Affords intercepting stream-stream invocations.
+
+    This is an EXPERIMENTAL API.
+    """
+
+    @abc.abstractmethod
+    def intercept_stream_stream(self, continuation, client_call_details,
+                                request_iterator):
+        """Intercepts a stream-stream invocation.
+
+          continuation: A function that proceeds with the invocation by
+            executing the next interceptor in chain or invoking the
+            actual RPC on the underlying Channel. It is the interceptor's
+            responsibility to call it if it decides to move the RPC forward.
+            The interceptor can use
+            `response_iterator = continuation(client_call_details,
+                                              request_iterator)`
+            to continue with the RPC. `continuation` returns an object that is
+            both a Call for the RPC and an iterator for response values.
+            Drawing response values from the returned Call-iterator may
+            raise RpcError indicating termination of the RPC with non-OK
+            status.
+          client_call_details: A ClientCallDetails object describing the
+            outgoing RPC.
+          request_iterator: An iterator that yields request values for the RPC.
+
+        Returns:
+            An object that is both a Call for the RPC and an iterator of
+            response values. Drawing response values from the returned
+            Call-iterator may raise RpcError indicating termination of
+            the RPC with non-OK status.
+        """
+        raise NotImplementedError()
+
+
 ############  Authentication & Authorization Interfaces & Classes  #############
 
 
@@ -962,6 +1126,34 @@
         raise NotImplementedError()
 
 
+####################  Service-Side Interceptor Interfaces  #####################
+
+
+class ServerInterceptor(six.with_metaclass(abc.ABCMeta)):
+    """Affords intercepting incoming RPCs on the service-side.
+
+    This is an EXPERIMENTAL API.
+    """
+
+    @abc.abstractmethod
+    def intercept_service(self, continuation, handler_call_details):
+        """Intercepts incoming RPCs before handing them over to a handler.
+
+        Args:
+          continuation: A function that takes a HandlerCallDetails and
+            proceeds to invoke the next interceptor in the chain, if any,
+            or the RPC handler lookup logic, with the call details passed
+            as an argument, and returns an RpcMethodHandler instance if
+            the RPC is considered serviced, or None otherwise.
+          handler_call_details: A HandlerCallDetails describing the RPC.
+
+        Returns:
+          An RpcMethodHandler with which the RPC may be serviced if the
+          interceptor chooses to service this RPC, or None otherwise.
+        """
+        raise NotImplementedError()
+
+
 #############################  Server Interface  ###############################
 
 
@@ -1376,53 +1568,88 @@
                             credentials._credentials)
 
 
+def intercept_channel(channel, *interceptors):
+    """Intercepts a channel through a set of interceptors.
+
+    This is an EXPERIMENTAL API.
+
+    Args:
+      channel: A Channel.
+      interceptors: Zero or more objects of type
+        UnaryUnaryClientInterceptor,
+        UnaryStreamClientInterceptor,
+        StreamUnaryClientInterceptor, or
+        StreamStreamClientInterceptor.
+        Interceptors are given control in the order they are listed.
+
+    Returns:
+      A Channel that intercepts each invocation via the provided interceptors.
+
+    Raises:
+      TypeError: If interceptor does not derive from any of
+        UnaryUnaryClientInterceptor,
+        UnaryStreamClientInterceptor,
+        StreamUnaryClientInterceptor, or
+        StreamStreamClientInterceptor.
+    """
+    from grpc import _interceptor  # pylint: disable=cyclic-import
+    return _interceptor.intercept_channel(channel, *interceptors)
+
+
 def server(thread_pool,
            handlers=None,
+           interceptors=None,
            options=None,
            maximum_concurrent_rpcs=None):
     """Creates a Server with which RPCs can be serviced.
 
-  Args:
-    thread_pool: A futures.ThreadPoolExecutor to be used by the Server
-      to execute RPC handlers.
-    handlers: An optional list of GenericRpcHandlers used for executing RPCs.
-      More handlers may be added by calling add_generic_rpc_handlers any time
-      before the server is started.
-    options: An optional list of key-value pairs (channel args in gRPC runtime)
-    to configure the channel.
-    maximum_concurrent_rpcs: The maximum number of concurrent RPCs this server
-      will service before returning RESOURCE_EXHAUSTED status, or None to
-      indicate no limit.
+    Args:
+      thread_pool: A futures.ThreadPoolExecutor to be used by the Server
+        to execute RPC handlers.
+      handlers: An optional list of GenericRpcHandlers used for executing RPCs.
+        More handlers may be added by calling add_generic_rpc_handlers any time
+        before the server is started.
+      interceptors: An optional list of ServerInterceptor objects that observe
+        and optionally manipulate the incoming RPCs before handing them over to
+        handlers. The interceptors are given control in the order they are
+        specified. This is an EXPERIMENTAL API.
+      options: An optional list of key-value pairs (channel args in gRPC runtime)
+      to configure the channel.
+      maximum_concurrent_rpcs: The maximum number of concurrent RPCs this server
+        will service before returning RESOURCE_EXHAUSTED status, or None to
+        indicate no limit.
 
-  Returns:
-    A Server object.
-  """
+    Returns:
+      A Server object.
+    """
     from grpc import _server  # pylint: disable=cyclic-import
     return _server.Server(thread_pool, () if handlers is None else handlers, ()
-                          if options is None else options,
-                          maximum_concurrent_rpcs)
+                          if interceptors is None else interceptors, () if
+                          options is None else options, maximum_concurrent_rpcs)
 
 
 ###################################  __all__  #################################
 
-__all__ = ('FutureTimeoutError', 'FutureCancelledError', 'Future',
-           'ChannelConnectivity', 'StatusCode', 'RpcError', 'RpcContext',
-           'Call', 'ChannelCredentials', 'CallCredentials',
-           'AuthMetadataContext', 'AuthMetadataPluginCallback',
-           'AuthMetadataPlugin', 'ServerCertificateConfiguration',
-           'ServerCredentials', 'UnaryUnaryMultiCallable',
-           'UnaryStreamMultiCallable', 'StreamUnaryMultiCallable',
-           'StreamStreamMultiCallable', 'Channel', 'ServicerContext',
-           'RpcMethodHandler', 'HandlerCallDetails', 'GenericRpcHandler',
-           'ServiceRpcHandler', 'Server', 'unary_unary_rpc_method_handler',
-           'unary_stream_rpc_method_handler', 'stream_unary_rpc_method_handler',
-           'stream_stream_rpc_method_handler',
-           'method_handlers_generic_handler', 'ssl_channel_credentials',
-           'metadata_call_credentials', 'access_token_call_credentials',
-           'composite_call_credentials', 'composite_channel_credentials',
-           'ssl_server_credentials', 'ssl_server_certificate_configuration',
-           'dynamic_ssl_server_credentials', 'channel_ready_future',
-           'insecure_channel', 'secure_channel', 'server',)
+__all__ = (
+    'FutureTimeoutError', 'FutureCancelledError', 'Future',
+    'ChannelConnectivity', 'StatusCode', 'RpcError', 'RpcContext', 'Call',
+    'ChannelCredentials', 'CallCredentials', 'AuthMetadataContext',
+    'AuthMetadataPluginCallback', 'AuthMetadataPlugin', 'ClientCallDetails',
+    'ServerCertificateConfiguration', 'ServerCredentials',
+    'UnaryUnaryMultiCallable', 'UnaryStreamMultiCallable',
+    'StreamUnaryMultiCallable', 'StreamStreamMultiCallable',
+    'UnaryUnaryClientInterceptor', 'UnaryStreamClientInterceptor',
+    'StreamUnaryClientInterceptor', 'StreamStreamClientInterceptor', 'Channel',
+    'ServicerContext', 'RpcMethodHandler', 'HandlerCallDetails',
+    'GenericRpcHandler', 'ServiceRpcHandler', 'Server', 'ServerInterceptor',
+    'unary_unary_rpc_method_handler', 'unary_stream_rpc_method_handler',
+    'stream_unary_rpc_method_handler', 'stream_stream_rpc_method_handler',
+    'method_handlers_generic_handler', 'ssl_channel_credentials',
+    'metadata_call_credentials', 'access_token_call_credentials',
+    'composite_call_credentials', 'composite_channel_credentials',
+    'ssl_server_credentials', 'ssl_server_certificate_configuration',
+    'dynamic_ssl_server_credentials', 'channel_ready_future',
+    'insecure_channel', 'secure_channel', 'intercept_channel', 'server',)
 
 ############################### Extension Shims ################################
 
diff --git a/src/python/grpcio/grpc/_channel.py b/src/python/grpcio/grpc/_channel.py
index d7456a3..3572737 100644
--- a/src/python/grpcio/grpc/_channel.py
+++ b/src/python/grpcio/grpc/_channel.py
@@ -129,12 +129,12 @@
 def _handle_event(event, state, response_deserializer):
     callbacks = []
     for batch_operation in event.batch_operations:
-        operation_type = batch_operation.type
+        operation_type = batch_operation.type()
         state.due.remove(operation_type)
         if operation_type == cygrpc.OperationType.receive_initial_metadata:
-            state.initial_metadata = batch_operation.received_metadata
+            state.initial_metadata = batch_operation.initial_metadata()
         elif operation_type == cygrpc.OperationType.receive_message:
-            serialized_response = batch_operation.received_message.bytes()
+            serialized_response = batch_operation.message()
             if serialized_response is not None:
                 response = _common.deserialize(serialized_response,
                                                response_deserializer)
@@ -144,18 +144,17 @@
                 else:
                     state.response = response
         elif operation_type == cygrpc.OperationType.receive_status_on_client:
-            state.trailing_metadata = batch_operation.received_metadata
+            state.trailing_metadata = batch_operation.trailing_metadata()
             if state.code is None:
                 code = _common.CYGRPC_STATUS_CODE_TO_STATUS_CODE.get(
-                    batch_operation.received_status_code)
+                    batch_operation.code())
                 if code is None:
                     state.code = grpc.StatusCode.UNKNOWN
                     state.details = _unknown_code_details(
-                        batch_operation.received_status_code,
-                        batch_operation.received_status_details)
+                        code, batch_operation.details())
                 else:
                     state.code = code
-                    state.details = batch_operation.received_status_details
+                    state.details = batch_operation.details()
             callbacks.extend(state.callbacks)
             state.callbacks = None
     return callbacks
@@ -200,7 +199,7 @@
                         _abort(state, grpc.StatusCode.INTERNAL, details)
                         return
                     else:
-                        operations = (cygrpc.operation_send_message(
+                        operations = (cygrpc.SendMessageOperation(
                             serialized_request, _EMPTY_FLAGS),)
                         call.start_client_batch(operations, event_handler)
                         state.due.add(cygrpc.OperationType.send_message)
@@ -216,7 +215,7 @@
         with state.condition:
             if state.code is None:
                 operations = (
-                    cygrpc.operation_send_close_from_client(_EMPTY_FLAGS),)
+                    cygrpc.SendCloseFromClientOperation(_EMPTY_FLAGS),)
                 call.start_client_batch(operations, event_handler)
                 state.due.add(cygrpc.OperationType.send_close_from_client)
 
@@ -319,7 +318,7 @@
                 event_handler = _event_handler(self._state, self._call,
                                                self._response_deserializer)
                 self._call.start_client_batch(
-                    (cygrpc.operation_receive_message(_EMPTY_FLAGS),),
+                    (cygrpc.ReceiveMessageOperation(_EMPTY_FLAGS),),
                     event_handler)
                 self._state.due.add(cygrpc.OperationType.receive_message)
             elif self._state.code is grpc.StatusCode.OK:
@@ -453,12 +452,12 @@
         else:
             state = _RPCState(_UNARY_UNARY_INITIAL_DUE, None, None, None, None)
             operations = (
-                cygrpc.operation_send_initial_metadata(metadata, _EMPTY_FLAGS),
-                cygrpc.operation_send_message(serialized_request, _EMPTY_FLAGS),
-                cygrpc.operation_send_close_from_client(_EMPTY_FLAGS),
-                cygrpc.operation_receive_initial_metadata(_EMPTY_FLAGS),
-                cygrpc.operation_receive_message(_EMPTY_FLAGS),
-                cygrpc.operation_receive_status_on_client(_EMPTY_FLAGS),)
+                cygrpc.SendInitialMetadataOperation(metadata, _EMPTY_FLAGS),
+                cygrpc.SendMessageOperation(serialized_request, _EMPTY_FLAGS),
+                cygrpc.SendCloseFromClientOperation(_EMPTY_FLAGS),
+                cygrpc.ReceiveInitialMetadataOperation(_EMPTY_FLAGS),
+                cygrpc.ReceiveMessageOperation(_EMPTY_FLAGS),
+                cygrpc.ReceiveStatusOnClientOperation(_EMPTY_FLAGS),)
             return state, operations, deadline, deadline_timespec, None
 
     def _blocking(self, request, timeout, metadata, credentials):
@@ -536,14 +535,14 @@
                                            self._response_deserializer)
             with state.condition:
                 call.start_client_batch(
-                    (cygrpc.operation_receive_initial_metadata(_EMPTY_FLAGS),),
+                    (cygrpc.ReceiveInitialMetadataOperation(_EMPTY_FLAGS),),
                     event_handler)
                 operations = (
-                    cygrpc.operation_send_initial_metadata(
-                        metadata, _EMPTY_FLAGS), cygrpc.operation_send_message(
+                    cygrpc.SendInitialMetadataOperation(
+                        metadata, _EMPTY_FLAGS), cygrpc.SendMessageOperation(
                             serialized_request, _EMPTY_FLAGS),
-                    cygrpc.operation_send_close_from_client(_EMPTY_FLAGS),
-                    cygrpc.operation_receive_status_on_client(_EMPTY_FLAGS),)
+                    cygrpc.SendCloseFromClientOperation(_EMPTY_FLAGS),
+                    cygrpc.ReceiveStatusOnClientOperation(_EMPTY_FLAGS),)
                 call_error = call.start_client_batch(operations, event_handler)
                 if call_error != cygrpc.CallError.ok:
                     _call_error_set_RPCstate(state, call_error, metadata)
@@ -573,12 +572,11 @@
             call.set_credentials(credentials._credentials)
         with state.condition:
             call.start_client_batch(
-                (cygrpc.operation_receive_initial_metadata(_EMPTY_FLAGS),),
-                None)
+                (cygrpc.ReceiveInitialMetadataOperation(_EMPTY_FLAGS),), None)
             operations = (
-                cygrpc.operation_send_initial_metadata(metadata, _EMPTY_FLAGS),
-                cygrpc.operation_receive_message(_EMPTY_FLAGS),
-                cygrpc.operation_receive_status_on_client(_EMPTY_FLAGS),)
+                cygrpc.SendInitialMetadataOperation(metadata, _EMPTY_FLAGS),
+                cygrpc.ReceiveMessageOperation(_EMPTY_FLAGS),
+                cygrpc.ReceiveStatusOnClientOperation(_EMPTY_FLAGS),)
             call_error = call.start_client_batch(operations, None)
             _check_call_error(call_error, metadata)
             _consume_request_iterator(request_iterator, state, call,
@@ -624,12 +622,12 @@
         event_handler = _event_handler(state, call, self._response_deserializer)
         with state.condition:
             call.start_client_batch(
-                (cygrpc.operation_receive_initial_metadata(_EMPTY_FLAGS),),
+                (cygrpc.ReceiveInitialMetadataOperation(_EMPTY_FLAGS),),
                 event_handler)
             operations = (
-                cygrpc.operation_send_initial_metadata(metadata, _EMPTY_FLAGS),
-                cygrpc.operation_receive_message(_EMPTY_FLAGS),
-                cygrpc.operation_receive_status_on_client(_EMPTY_FLAGS),)
+                cygrpc.SendInitialMetadataOperation(metadata, _EMPTY_FLAGS),
+                cygrpc.ReceiveMessageOperation(_EMPTY_FLAGS),
+                cygrpc.ReceiveStatusOnClientOperation(_EMPTY_FLAGS),)
             call_error = call.start_client_batch(operations, event_handler)
             if call_error != cygrpc.CallError.ok:
                 _call_error_set_RPCstate(state, call_error, metadata)
@@ -664,11 +662,11 @@
         event_handler = _event_handler(state, call, self._response_deserializer)
         with state.condition:
             call.start_client_batch(
-                (cygrpc.operation_receive_initial_metadata(_EMPTY_FLAGS),),
+                (cygrpc.ReceiveInitialMetadataOperation(_EMPTY_FLAGS),),
                 event_handler)
             operations = (
-                cygrpc.operation_send_initial_metadata(metadata, _EMPTY_FLAGS),
-                cygrpc.operation_receive_status_on_client(_EMPTY_FLAGS),)
+                cygrpc.SendInitialMetadataOperation(metadata, _EMPTY_FLAGS),
+                cygrpc.ReceiveStatusOnClientOperation(_EMPTY_FLAGS),)
             call_error = call.start_client_batch(operations, event_handler)
             if call_error != cygrpc.CallError.ok:
                 _call_error_set_RPCstate(state, call_error, metadata)
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi
index 660263f..7f91965 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi
@@ -17,6 +17,7 @@
 
 # Typedef types with approximately the same semantics to provide their names to
 # Cython
+ctypedef unsigned char uint8_t
 ctypedef int int32_t
 ctypedef unsigned uint32_t
 ctypedef long int64_t
@@ -25,6 +26,7 @@
 cdef extern from "grpc/support/alloc.h":
 
   void *gpr_malloc(size_t size) nogil
+  void *gpr_zalloc(size_t size) nogil
   void gpr_free(void *ptr) nogil
   void *gpr_realloc(void *p, size_t size) nogil
 
@@ -190,6 +192,18 @@
     size_t arguments_length "num_args"
     grpc_arg *arguments "args"
 
+  ctypedef enum grpc_compression_level:
+    GRPC_COMPRESS_LEVEL_NONE
+    GRPC_COMPRESS_LEVEL_LOW
+    GRPC_COMPRESS_LEVEL_MED
+    GRPC_COMPRESS_LEVEL_HIGH
+
+  ctypedef enum grpc_stream_compression_level:
+    GRPC_STREAM_COMPRESS_LEVEL_NONE
+    GRPC_STREAM_COMPRESS_LEVEL_LOW
+    GRPC_STREAM_COMPRESS_LEVEL_MED
+    GRPC_STREAM_COMPRESS_LEVEL_HIGH
+
   ctypedef enum grpc_call_error:
     GRPC_CALL_OK
     GRPC_CALL_ERROR
@@ -265,9 +279,19 @@
     GRPC_OP_RECV_STATUS_ON_CLIENT
     GRPC_OP_RECV_CLOSE_ON_SERVER
 
+  ctypedef struct grpc_op_send_initial_metadata_maybe_compression_level:
+    uint8_t is_set
+    grpc_compression_level level
+
+  ctypedef struct grpc_op_send_initial_metadata_maybe_stream_compression_level:
+    uint8_t is_set
+    grpc_stream_compression_level level
+
   ctypedef struct grpc_op_data_send_initial_metadata:
     size_t count
     grpc_metadata *metadata
+    grpc_op_send_initial_metadata_maybe_compression_level maybe_compression_level
+    grpc_op_send_initial_metadata_maybe_stream_compression_level maybe_stream_compression_level
 
   ctypedef struct grpc_op_data_send_status_from_server:
     size_t trailing_metadata_count
@@ -524,7 +548,7 @@
 
   grpc_auth_property_iterator grpc_auth_context_property_iterator(
       const grpc_auth_context *ctx)
- 
+
   grpc_auth_property_iterator grpc_auth_context_peer_identity(
       const grpc_auth_context *ctx)
 
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/grpc_string.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/grpc_string.pyx.pxi
index e3cad9a..53e06a1 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/grpc_string.pyx.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/grpc_string.pyx.pxi
@@ -26,15 +26,20 @@
     raise TypeError('Expected bytes, str, or unicode, not {}'.format(type(s)))
 
 
-cdef bytes _encode(str native_string_or_none):
-  if native_string_or_none is None:
+# TODO(https://github.com/grpc/grpc/issues/13782): It would be nice for us if
+# the type of metadata that we accept were exactly the same as the type of
+# metadata that we deliver to our users (so "str" for this function's
+# parameter rather than "object"), but would it be nice for our users? Right
+# now we haven't yet heard from enough users to know one way or another.
+cdef bytes _encode(object string_or_none):
+  if string_or_none is None:
     return b''
-  elif isinstance(native_string_or_none, (bytes,)):
-    return <bytes>native_string_or_none
-  elif isinstance(native_string_or_none, (unicode,)):
-    return native_string_or_none.encode('ascii')
+  elif isinstance(string_or_none, (bytes,)):
+    return <bytes>string_or_none
+  elif isinstance(string_or_none, (unicode,)):
+    return string_or_none.encode('ascii')
   else:
-    raise TypeError('Expected str, not {}'.format(type(native_string_or_none)))
+    raise TypeError('Expected str, not {}'.format(type(string_or_none)))
 
 
 cdef str _decode(bytes bytestring):
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/operation.pxd.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/operation.pxd.pxi
new file mode 100644
index 0000000..bfbe277
--- /dev/null
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/operation.pxd.pxi
@@ -0,0 +1,109 @@
+# 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.
+
+
+cdef class Operation:
+
+  cdef void c(self)
+  cdef void un_c(self)
+
+  # TODO(https://github.com/grpc/grpc/issues/7950): Eliminate this!
+  cdef grpc_op c_op
+
+
+cdef class SendInitialMetadataOperation(Operation):
+
+  cdef readonly object _initial_metadata;
+  cdef readonly int _flags
+  cdef grpc_metadata *_c_initial_metadata
+  cdef size_t _c_initial_metadata_count
+
+  cdef void c(self)
+  cdef void un_c(self)
+
+
+cdef class SendMessageOperation(Operation):
+
+  cdef readonly bytes _message
+  cdef readonly int _flags
+  cdef grpc_byte_buffer *_c_message_byte_buffer
+
+  cdef void c(self)
+  cdef void un_c(self)
+
+
+cdef class SendCloseFromClientOperation(Operation):
+
+  cdef readonly int _flags
+
+  cdef void c(self)
+  cdef void un_c(self)
+
+
+cdef class SendStatusFromServerOperation(Operation):
+
+  cdef readonly object _trailing_metadata
+  cdef readonly object _code
+  cdef readonly object _details
+  cdef readonly int _flags
+  cdef grpc_metadata *_c_trailing_metadata
+  cdef size_t _c_trailing_metadata_count
+  cdef grpc_slice _c_details
+
+  cdef void c(self)
+  cdef void un_c(self)
+
+
+cdef class ReceiveInitialMetadataOperation(Operation):
+
+  cdef readonly int _flags
+  cdef tuple _initial_metadata
+  cdef grpc_metadata_array _c_initial_metadata
+
+  cdef void c(self)
+  cdef void un_c(self)
+
+
+cdef class ReceiveMessageOperation(Operation):
+
+  cdef readonly int _flags
+  cdef grpc_byte_buffer *_c_message_byte_buffer
+  cdef bytes _message
+
+  cdef void c(self)
+  cdef void un_c(self)
+
+
+cdef class ReceiveStatusOnClientOperation(Operation):
+
+  cdef readonly int _flags
+  cdef grpc_metadata_array _c_trailing_metadata
+  cdef grpc_status_code _c_code
+  cdef grpc_slice _c_details
+  cdef tuple _trailing_metadata
+  cdef object _code
+  cdef str _details
+
+  cdef void c(self)
+  cdef void un_c(self)
+
+
+cdef class ReceiveCloseOnServerOperation(Operation):
+
+  cdef readonly int _flags
+  cdef object _cancelled
+  cdef int _c_cancelled
+
+  cdef void c(self)
+  cdef void un_c(self)
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/operation.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/operation.pyx.pxi
new file mode 100644
index 0000000..3c91abf
--- /dev/null
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/operation.pyx.pxi
@@ -0,0 +1,238 @@
+# 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.
+
+
+cdef class Operation:
+
+  cdef void c(self):
+    raise NotImplementedError()
+
+  cdef void un_c(self):
+    raise NotImplementedError()
+
+
+cdef class SendInitialMetadataOperation(Operation):
+
+  def __cinit__(self, initial_metadata, flags):
+    self._initial_metadata = initial_metadata
+    self._flags = flags
+
+  def type(self):
+    return GRPC_OP_SEND_INITIAL_METADATA
+
+  cdef void c(self):
+    self.c_op.type = GRPC_OP_SEND_INITIAL_METADATA
+    self.c_op.flags = self._flags
+    _store_c_metadata(
+        self._initial_metadata, &self._c_initial_metadata,
+        &self._c_initial_metadata_count)
+    self.c_op.data.send_initial_metadata.metadata = self._c_initial_metadata
+    self.c_op.data.send_initial_metadata.count = self._c_initial_metadata_count
+    self.c_op.data.send_initial_metadata.maybe_compression_level.is_set = 0
+    self.c_op.data.send_initial_metadata.maybe_stream_compression_level.is_set = 0
+
+  cdef void un_c(self):
+    _release_c_metadata(
+        self._c_initial_metadata, self._c_initial_metadata_count)
+
+
+cdef class SendMessageOperation(Operation):
+
+  def __cinit__(self, bytes message, int flags):
+    self._message = message
+    self._flags = flags
+
+  def type(self):
+    return GRPC_OP_SEND_MESSAGE
+
+  cdef void c(self):
+    self.c_op.type = GRPC_OP_SEND_MESSAGE
+    self.c_op.flags = self._flags
+    cdef grpc_slice message_slice = grpc_slice_from_copied_buffer(
+        self._message, len(self._message))
+    self._c_message_byte_buffer = grpc_raw_byte_buffer_create(
+        &message_slice, 1)
+    grpc_slice_unref(message_slice)
+    self.c_op.data.send_message.send_message = self._c_message_byte_buffer
+
+  cdef void un_c(self):
+    grpc_byte_buffer_destroy(self._c_message_byte_buffer)
+
+
+cdef class SendCloseFromClientOperation(Operation):
+
+  def __cinit__(self, int flags):
+    self._flags = flags
+
+  def type(self):
+    return GRPC_OP_SEND_CLOSE_FROM_CLIENT
+
+  cdef void c(self):
+    self.c_op.type = GRPC_OP_SEND_CLOSE_FROM_CLIENT
+    self.c_op.flags = self._flags
+
+  cdef void un_c(self):
+    pass
+
+
+cdef class SendStatusFromServerOperation(Operation):
+
+  def __cinit__(self, trailing_metadata, code, object details, int flags):
+    self._trailing_metadata = trailing_metadata
+    self._code = code
+    self._details = details
+    self._flags = flags
+
+  def type(self):
+    return GRPC_OP_SEND_STATUS_FROM_SERVER
+
+  cdef void c(self):
+    self.c_op.type = GRPC_OP_SEND_STATUS_FROM_SERVER
+    self.c_op.flags = self._flags
+    _store_c_metadata(
+        self._trailing_metadata, &self._c_trailing_metadata,
+        &self._c_trailing_metadata_count)
+    self.c_op.data.send_status_from_server.trailing_metadata = (
+        self._c_trailing_metadata)
+    self.c_op.data.send_status_from_server.trailing_metadata_count = (
+        self._c_trailing_metadata_count)
+    self.c_op.data.send_status_from_server.status = self._code
+    self._c_details = _slice_from_bytes(_encode(self._details))
+    self.c_op.data.send_status_from_server.status_details = &self._c_details
+
+  cdef void un_c(self):
+    grpc_slice_unref(self._c_details)
+    _release_c_metadata(
+        self._c_trailing_metadata, self._c_trailing_metadata_count)
+
+
+cdef class ReceiveInitialMetadataOperation(Operation):
+
+  def __cinit__(self, flags):
+    self._flags = flags
+
+  def type(self):
+    return GRPC_OP_RECV_INITIAL_METADATA
+
+  cdef void c(self):
+    self.c_op.type = GRPC_OP_RECV_INITIAL_METADATA
+    self.c_op.flags = self._flags
+    grpc_metadata_array_init(&self._c_initial_metadata)
+    self.c_op.data.receive_initial_metadata.receive_initial_metadata = (
+        &self._c_initial_metadata)
+
+  cdef void un_c(self):
+    self._initial_metadata = _metadata(&self._c_initial_metadata)
+    grpc_metadata_array_destroy(&self._c_initial_metadata)
+
+  def initial_metadata(self):
+    return self._initial_metadata
+
+
+cdef class ReceiveMessageOperation(Operation):
+
+  def __cinit__(self, flags):
+    self._flags = flags
+
+  def type(self):
+    return GRPC_OP_RECV_MESSAGE
+
+  cdef void c(self):
+    self.c_op.type = GRPC_OP_RECV_MESSAGE
+    self.c_op.flags = self._flags
+    self.c_op.data.receive_message.receive_message = (
+        &self._c_message_byte_buffer)
+
+  cdef void un_c(self):
+    cdef grpc_byte_buffer_reader message_reader
+    cdef bint message_reader_status
+    cdef grpc_slice message_slice
+    cdef size_t message_slice_length
+    cdef void *message_slice_pointer
+    if self._c_message_byte_buffer != NULL:
+      message_reader_status = grpc_byte_buffer_reader_init(
+          &message_reader, self._c_message_byte_buffer)
+      if message_reader_status:
+        message = bytearray()
+        while grpc_byte_buffer_reader_next(&message_reader, &message_slice):
+          message_slice_pointer = grpc_slice_start_ptr(message_slice)
+          message_slice_length = grpc_slice_length(message_slice)
+          message += (<char *>message_slice_pointer)[:message_slice_length]
+          grpc_slice_unref(message_slice)
+        grpc_byte_buffer_reader_destroy(&message_reader)
+        self._message = bytes(message)
+      else:
+        self._message = None
+      grpc_byte_buffer_destroy(self._c_message_byte_buffer)
+    else:
+      self._message = None
+
+  def message(self):
+    return self._message
+
+
+cdef class ReceiveStatusOnClientOperation(Operation):
+
+  def __cinit__(self, flags):
+    self._flags = flags
+
+  def type(self):
+    return GRPC_OP_RECV_STATUS_ON_CLIENT
+
+  cdef void c(self):
+    self.c_op.type = GRPC_OP_RECV_STATUS_ON_CLIENT
+    self.c_op.flags = self._flags
+    grpc_metadata_array_init(&self._c_trailing_metadata)
+    self.c_op.data.receive_status_on_client.trailing_metadata = (
+        &self._c_trailing_metadata)
+    self.c_op.data.receive_status_on_client.status = (
+        &self._c_code)
+    self.c_op.data.receive_status_on_client.status_details = (
+        &self._c_details)
+
+  cdef void un_c(self):
+    self._trailing_metadata = _metadata(&self._c_trailing_metadata)
+    grpc_metadata_array_destroy(&self._c_trailing_metadata)
+    self._code = self._c_code
+    self._details = _decode(_slice_bytes(self._c_details))
+    grpc_slice_unref(self._c_details)
+
+  def trailing_metadata(self):
+    return self._trailing_metadata
+
+  def code(self):
+    return self._code
+
+  def details(self):
+    return self._details
+
+
+cdef class ReceiveCloseOnServerOperation(Operation):
+
+  def __cinit__(self, flags):
+    self._flags = flags
+
+  def type(self):
+    return GRPC_OP_RECV_CLOSE_ON_SERVER
+
+  cdef void c(self):
+    self.c_op.type = GRPC_OP_RECV_CLOSE_ON_SERVER
+    self.c_op.flags = self._flags
+    self.c_op.data.receive_close_on_server.cancelled = &self._c_cancelled
+
+  cdef void un_c(self):
+    self._cancelled = bool(self._c_cancelled)
+
+  def cancelled(self):
+    return self._cancelled
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/records.pxd.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/records.pxd.pxi
index 594fdb1..537cf2b 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/records.pxd.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/records.pxd.pxi
@@ -65,11 +65,6 @@
   cdef readonly object batch_operations
 
 
-cdef class ByteBuffer:
-
-  cdef grpc_byte_buffer *c_byte_buffer
-
-
 cdef class SslPemKeyCertPair:
 
   cdef grpc_ssl_pem_key_cert_pair c_pair
@@ -89,22 +84,6 @@
   cdef list args
 
 
-cdef class Operation:
-
-  cdef grpc_op c_op
-  cdef bint _c_metadata_needs_release
-  cdef size_t _c_metadata_count
-  cdef grpc_metadata *_c_metadata
-  cdef ByteBuffer _received_message
-  cdef bint _c_metadata_array_needs_destruction
-  cdef grpc_metadata_array _c_metadata_array
-  cdef grpc_status_code _received_status_code
-  cdef grpc_slice _status_details
-  cdef int _received_cancelled
-  cdef readonly bint is_valid
-  cdef object references
-
-
 cdef class CompressionOptions:
 
   cdef grpc_compression_options c_options
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx.pxi
index 5877591..99f8ffa 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx.pxi
@@ -229,13 +229,15 @@
     self.c_nops = 0 if self._operations is None else len(self._operations)
     if 0 < self.c_nops:
       self.c_ops = <grpc_op *>gpr_malloc(sizeof(grpc_op) * self.c_nops)
-      for index in range(self.c_nops):
-        self.c_ops[index] = (<Operation>(self._operations[index])).c_op
+      for index, operation in enumerate(self._operations):
+        (<Operation>operation).c()
+        self.c_ops[index] = (<Operation>operation).c_op
 
   cdef object release_ops(self):
     if 0 < self.c_nops:
       for index, operation in enumerate(self._operations):
         (<Operation>operation).c_op = self.c_ops[index]
+        (<Operation>operation).un_c()
       gpr_free(self.c_ops)
       return self._operations
     else:
@@ -260,69 +262,6 @@
     self.is_new_request = is_new_request
 
 
-cdef class ByteBuffer:
-
-  def __cinit__(self, bytes data):
-    grpc_init()
-    if data is None:
-      self.c_byte_buffer = NULL
-      return
-
-    cdef char *c_data = data
-    cdef grpc_slice data_slice
-    cdef size_t data_length = len(data)
-    with nogil:
-      data_slice = grpc_slice_from_copied_buffer(c_data, data_length)
-    with nogil:
-      self.c_byte_buffer = grpc_raw_byte_buffer_create(
-          &data_slice, 1)
-    with nogil:
-      grpc_slice_unref(data_slice)
-
-  def bytes(self):
-    cdef grpc_byte_buffer_reader reader
-    cdef grpc_slice data_slice
-    cdef size_t data_slice_length
-    cdef void *data_slice_pointer
-    cdef bint reader_status
-    if self.c_byte_buffer != NULL:
-      with nogil:
-        reader_status = grpc_byte_buffer_reader_init(
-            &reader, self.c_byte_buffer)
-      if not reader_status:
-        return None
-      result = bytearray()
-      with nogil:
-        while grpc_byte_buffer_reader_next(&reader, &data_slice):
-          data_slice_pointer = grpc_slice_start_ptr(data_slice)
-          data_slice_length = grpc_slice_length(data_slice)
-          with gil:
-            result += (<char *>data_slice_pointer)[:data_slice_length]
-          grpc_slice_unref(data_slice)
-      with nogil:
-        grpc_byte_buffer_reader_destroy(&reader)
-      return bytes(result)
-    else:
-      return None
-
-  def __len__(self):
-    cdef size_t result
-    if self.c_byte_buffer != NULL:
-      with nogil:
-        result = grpc_byte_buffer_length(self.c_byte_buffer)
-      return result
-    else:
-      return 0
-
-  def __str__(self):
-    return self.bytes()
-
-  def __dealloc__(self):
-    if self.c_byte_buffer != NULL:
-      grpc_byte_buffer_destroy(self.c_byte_buffer)
-    grpc_shutdown()
-
-
 cdef class SslPemKeyCertPair:
 
   def __cinit__(self, bytes private_key, bytes certificate_chain):
@@ -365,7 +304,7 @@
     elif hasattr(value, '__int__'):
       # Pointer objects must override __int__() to return
       # the underlying C address (Python ints are word size).  The
-      # lifecycle of the pointer is fixed to the lifecycle of the 
+      # lifecycle of the pointer is fixed to the lifecycle of the
       # python object wrapping it.
       self.ptr_vtable.copy = &copy_ptr
       self.ptr_vtable.destroy = &destroy_ptr
@@ -407,185 +346,6 @@
     return self.args[i]
 
 
-cdef class Operation:
-
-  def __cinit__(self):
-    grpc_init()
-    self.references = []
-    self._c_metadata_needs_release = False
-    self._c_metadata_array_needs_destruction = False
-    self._status_details = grpc_empty_slice()
-    self.is_valid = False
-
-  @property
-  def type(self):
-    return self.c_op.type
-
-  @property
-  def flags(self):
-    return self.c_op.flags
-
-  @property
-  def has_status(self):
-    return self.c_op.type == GRPC_OP_RECV_STATUS_ON_CLIENT
-
-  @property
-  def received_message(self):
-    if self.c_op.type != GRPC_OP_RECV_MESSAGE:
-      raise TypeError("self must be an operation receiving a message")
-    return self._received_message
-
-  @property
-  def received_message_or_none(self):
-    if self.c_op.type != GRPC_OP_RECV_MESSAGE:
-      return None
-    return self._received_message
-
-  @property
-  def received_metadata(self):
-    if (self.c_op.type != GRPC_OP_RECV_INITIAL_METADATA and
-        self.c_op.type != GRPC_OP_RECV_STATUS_ON_CLIENT):
-      raise TypeError("self must be an operation receiving metadata")
-    return _metadata(&self._c_metadata_array)
-
-  @property
-  def received_status_code(self):
-    if self.c_op.type != GRPC_OP_RECV_STATUS_ON_CLIENT:
-      raise TypeError("self must be an operation receiving a status code")
-    return self._received_status_code
-
-  @property
-  def received_status_code_or_none(self):
-    if self.c_op.type != GRPC_OP_RECV_STATUS_ON_CLIENT:
-      return None
-    return self._received_status_code
-
-  @property
-  def received_status_details(self):
-    if self.c_op.type != GRPC_OP_RECV_STATUS_ON_CLIENT:
-      raise TypeError("self must be an operation receiving status details")
-    return _slice_bytes(self._status_details)
-
-  @property
-  def received_status_details_or_none(self):
-    if self.c_op.type != GRPC_OP_RECV_STATUS_ON_CLIENT:
-      return None
-    return _slice_bytes(self._status_details)
-
-  @property
-  def received_cancelled(self):
-    if self.c_op.type != GRPC_OP_RECV_CLOSE_ON_SERVER:
-      raise TypeError("self must be an operation receiving cancellation "
-                      "information")
-    return False if self._received_cancelled == 0 else True
-
-  @property
-  def received_cancelled_or_none(self):
-    if self.c_op.type != GRPC_OP_RECV_CLOSE_ON_SERVER:
-      return None
-    return False if self._received_cancelled == 0 else True
-
-  def __dealloc__(self):
-    if self._c_metadata_needs_release:
-      _release_c_metadata(self._c_metadata, self._c_metadata_count)
-    if self._c_metadata_array_needs_destruction:
-      grpc_metadata_array_destroy(&self._c_metadata_array)
-    grpc_slice_unref(self._status_details)
-    grpc_shutdown()
-
-def operation_send_initial_metadata(metadata, int flags):
-  cdef Operation op = Operation()
-  op.c_op.type = GRPC_OP_SEND_INITIAL_METADATA
-  op.c_op.flags = flags
-  _store_c_metadata(metadata, &op._c_metadata, &op._c_metadata_count)
-  op._c_metadata_needs_release = True
-  op.c_op.data.send_initial_metadata.count = op._c_metadata_count
-  op.c_op.data.send_initial_metadata.metadata = op._c_metadata
-  op.is_valid = True
-  return op
-
-def operation_send_message(data, int flags):
-  cdef Operation op = Operation()
-  op.c_op.type = GRPC_OP_SEND_MESSAGE
-  op.c_op.flags = flags
-  byte_buffer = ByteBuffer(data)
-  op.c_op.data.send_message.send_message = byte_buffer.c_byte_buffer
-  op.references.append(byte_buffer)
-  op.is_valid = True
-  return op
-
-def operation_send_close_from_client(int flags):
-  cdef Operation op = Operation()
-  op.c_op.type = GRPC_OP_SEND_CLOSE_FROM_CLIENT
-  op.c_op.flags = flags
-  op.is_valid = True
-  return op
-
-def operation_send_status_from_server(
-    metadata, grpc_status_code code, bytes details, int flags):
-  cdef Operation op = Operation()
-  op.c_op.type = GRPC_OP_SEND_STATUS_FROM_SERVER
-  op.c_op.flags = flags
-  _store_c_metadata(metadata, &op._c_metadata, &op._c_metadata_count)
-  op._c_metadata_needs_release = True
-  op.c_op.data.send_status_from_server.trailing_metadata_count = (
-      op._c_metadata_count)
-  op.c_op.data.send_status_from_server.trailing_metadata = op._c_metadata
-  op.c_op.data.send_status_from_server.status = code
-  grpc_slice_unref(op._status_details)
-  op._status_details = _slice_from_bytes(details)
-  op.c_op.data.send_status_from_server.status_details = &op._status_details
-  op.is_valid = True
-  return op
-
-def operation_receive_initial_metadata(int flags):
-  cdef Operation op = Operation()
-  op.c_op.type = GRPC_OP_RECV_INITIAL_METADATA
-  op.c_op.flags = flags
-  grpc_metadata_array_init(&op._c_metadata_array)
-  op.c_op.data.receive_initial_metadata.receive_initial_metadata = (
-      &op._c_metadata_array)
-  op._c_metadata_array_needs_destruction = True
-  op.is_valid = True
-  return op
-
-def operation_receive_message(int flags):
-  cdef Operation op = Operation()
-  op.c_op.type = GRPC_OP_RECV_MESSAGE
-  op.c_op.flags = flags
-  op._received_message = ByteBuffer(None)
-  # n.b. the c_op.data.receive_message field needs to be deleted by us,
-  # anyway, so we just let that be handled by the ByteBuffer() we allocated
-  # the line before.
-  op.c_op.data.receive_message.receive_message = (
-      &op._received_message.c_byte_buffer)
-  op.is_valid = True
-  return op
-
-def operation_receive_status_on_client(int flags):
-  cdef Operation op = Operation()
-  op.c_op.type = GRPC_OP_RECV_STATUS_ON_CLIENT
-  op.c_op.flags = flags
-  grpc_metadata_array_init(&op._c_metadata_array)
-  op.c_op.data.receive_status_on_client.trailing_metadata = (
-      &op._c_metadata_array)
-  op._c_metadata_array_needs_destruction = True
-  op.c_op.data.receive_status_on_client.status = (
-      &op._received_status_code)
-  op.c_op.data.receive_status_on_client.status_details = (
-      &op._status_details)
-  op.is_valid = True
-  return op
-
-def operation_receive_close_on_server(int flags):
-  cdef Operation op = Operation()
-  op.c_op.type = GRPC_OP_RECV_CLOSE_ON_SERVER
-  op.c_op.flags = flags
-  op.c_op.data.receive_close_on_server.cancelled = &op._received_cancelled
-  op.is_valid = True
-  return op
-
-
 cdef class CompressionOptions:
 
   def __cinit__(self):
diff --git a/src/python/grpcio/grpc/_cython/cygrpc.pxd b/src/python/grpcio/grpc/_cython/cygrpc.pxd
index 6fc5638..ad229de 100644
--- a/src/python/grpcio/grpc/_cython/cygrpc.pxd
+++ b/src/python/grpcio/grpc/_cython/cygrpc.pxd
@@ -19,6 +19,7 @@
 include "_cygrpc/credentials.pxd.pxi"
 include "_cygrpc/completion_queue.pxd.pxi"
 include "_cygrpc/metadata.pxd.pxi"
+include "_cygrpc/operation.pxd.pxi"
 include "_cygrpc/records.pxd.pxi"
 include "_cygrpc/security.pxd.pxi"
 include "_cygrpc/server.pxd.pxi"
diff --git a/src/python/grpcio/grpc/_cython/cygrpc.pyx b/src/python/grpcio/grpc/_cython/cygrpc.pyx
index d605229..0964fb6 100644
--- a/src/python/grpcio/grpc/_cython/cygrpc.pyx
+++ b/src/python/grpcio/grpc/_cython/cygrpc.pyx
@@ -26,6 +26,7 @@
 include "_cygrpc/credentials.pyx.pxi"
 include "_cygrpc/completion_queue.pyx.pxi"
 include "_cygrpc/metadata.pyx.pxi"
+include "_cygrpc/operation.pyx.pxi"
 include "_cygrpc/records.pyx.pxi"
 include "_cygrpc/security.pyx.pxi"
 include "_cygrpc/server.pyx.pxi"
diff --git a/src/python/grpcio/grpc/_grpcio_metadata.py b/src/python/grpcio/grpc/_grpcio_metadata.py
index 8ebefbf..2b594c0 100644
--- a/src/python/grpcio/grpc/_grpcio_metadata.py
+++ b/src/python/grpcio/grpc/_grpcio_metadata.py
@@ -14,4 +14,4 @@
 
 # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio/grpc/_grpcio_metadata.py.template`!!!
 
-__version__ = """1.8.0rc2"""
+__version__ = """1.8.2"""
diff --git a/src/python/grpcio/grpc/_interceptor.py b/src/python/grpcio/grpc/_interceptor.py
new file mode 100644
index 0000000..fffb269
--- /dev/null
+++ b/src/python/grpcio/grpc/_interceptor.py
@@ -0,0 +1,318 @@
+# 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.
+"""Implementation of gRPC Python interceptors."""
+
+import collections
+import sys
+
+import grpc
+
+
+class _ServicePipeline(object):
+
+    def __init__(self, interceptors):
+        self.interceptors = tuple(interceptors)
+
+    def _continuation(self, thunk, index):
+        return lambda context: self._intercept_at(thunk, index, context)
+
+    def _intercept_at(self, thunk, index, context):
+        if index < len(self.interceptors):
+            interceptor = self.interceptors[index]
+            thunk = self._continuation(thunk, index + 1)
+            return interceptor.intercept_service(thunk, context)
+        else:
+            return thunk(context)
+
+    def execute(self, thunk, context):
+        return self._intercept_at(thunk, 0, context)
+
+
+def service_pipeline(interceptors):
+    return _ServicePipeline(interceptors) if interceptors else None
+
+
+class _ClientCallDetails(
+        collections.namedtuple('_ClientCallDetails',
+                               ('method', 'timeout', 'metadata',
+                                'credentials')), grpc.ClientCallDetails):
+    pass
+
+
+class _LocalFailure(grpc.RpcError, grpc.Future, grpc.Call):
+
+    def __init__(self, exception, traceback):
+        super(_LocalFailure, self).__init__()
+        self._exception = exception
+        self._traceback = traceback
+
+    def initial_metadata(self):
+        return None
+
+    def trailing_metadata(self):
+        return None
+
+    def code(self):
+        return grpc.StatusCode.INTERNAL
+
+    def details(self):
+        return 'Exception raised while intercepting the RPC'
+
+    def cancel(self):
+        return False
+
+    def cancelled(self):
+        return False
+
+    def running(self):
+        return False
+
+    def done(self):
+        return True
+
+    def result(self, ignored_timeout=None):
+        raise self._exception
+
+    def exception(self, ignored_timeout=None):
+        return self._exception
+
+    def traceback(self, ignored_timeout=None):
+        return self._traceback
+
+    def add_done_callback(self, fn):
+        fn(self)
+
+    def __iter__(self):
+        return self
+
+    def next(self):
+        raise self._exception
+
+
+class _UnaryUnaryMultiCallable(grpc.UnaryUnaryMultiCallable):
+
+    def __init__(self, thunk, method, interceptor):
+        self._thunk = thunk
+        self._method = method
+        self._interceptor = interceptor
+
+    def __call__(self, request, timeout=None, metadata=None, credentials=None):
+        call_future = self.future(
+            request,
+            timeout=timeout,
+            metadata=metadata,
+            credentials=credentials)
+        return call_future.result()
+
+    def with_call(self, request, timeout=None, metadata=None, credentials=None):
+        call_future = self.future(
+            request,
+            timeout=timeout,
+            metadata=metadata,
+            credentials=credentials)
+        return call_future.result(), call_future
+
+    def future(self, request, timeout=None, metadata=None, credentials=None):
+
+        def continuation(client_call_details, request):
+            return self._thunk(client_call_details.method).future(
+                request,
+                timeout=client_call_details.timeout,
+                metadata=client_call_details.metadata,
+                credentials=client_call_details.credentials)
+
+        client_call_details = _ClientCallDetails(self._method, timeout,
+                                                 metadata, credentials)
+        try:
+            return self._interceptor.intercept_unary_unary(
+                continuation, client_call_details, request)
+        except Exception as exception:  # pylint:disable=broad-except
+            return _LocalFailure(exception, sys.exc_info()[2])
+
+
+class _UnaryStreamMultiCallable(grpc.UnaryStreamMultiCallable):
+
+    def __init__(self, thunk, method, interceptor):
+        self._thunk = thunk
+        self._method = method
+        self._interceptor = interceptor
+
+    def __call__(self, request, timeout=None, metadata=None, credentials=None):
+
+        def continuation(client_call_details, request):
+            return self._thunk(client_call_details.method)(
+                request,
+                timeout=client_call_details.timeout,
+                metadata=client_call_details.metadata,
+                credentials=client_call_details.credentials)
+
+        client_call_details = _ClientCallDetails(self._method, timeout,
+                                                 metadata, credentials)
+        try:
+            return self._interceptor.intercept_unary_stream(
+                continuation, client_call_details, request)
+        except Exception as exception:  # pylint:disable=broad-except
+            return _LocalFailure(exception, sys.exc_info()[2])
+
+
+class _StreamUnaryMultiCallable(grpc.StreamUnaryMultiCallable):
+
+    def __init__(self, thunk, method, interceptor):
+        self._thunk = thunk
+        self._method = method
+        self._interceptor = interceptor
+
+    def __call__(self,
+                 request_iterator,
+                 timeout=None,
+                 metadata=None,
+                 credentials=None):
+        call_future = self.future(
+            request_iterator,
+            timeout=timeout,
+            metadata=metadata,
+            credentials=credentials)
+        return call_future.result()
+
+    def with_call(self,
+                  request_iterator,
+                  timeout=None,
+                  metadata=None,
+                  credentials=None):
+        call_future = self.future(
+            request_iterator,
+            timeout=timeout,
+            metadata=metadata,
+            credentials=credentials)
+        return call_future.result(), call_future
+
+    def future(self,
+               request_iterator,
+               timeout=None,
+               metadata=None,
+               credentials=None):
+
+        def continuation(client_call_details, request_iterator):
+            return self._thunk(client_call_details.method).future(
+                request_iterator,
+                timeout=client_call_details.timeout,
+                metadata=client_call_details.metadata,
+                credentials=client_call_details.credentials)
+
+        client_call_details = _ClientCallDetails(self._method, timeout,
+                                                 metadata, credentials)
+
+        try:
+            return self._interceptor.intercept_stream_unary(
+                continuation, client_call_details, request_iterator)
+        except Exception as exception:  # pylint:disable=broad-except
+            return _LocalFailure(exception, sys.exc_info()[2])
+
+
+class _StreamStreamMultiCallable(grpc.StreamStreamMultiCallable):
+
+    def __init__(self, thunk, method, interceptor):
+        self._thunk = thunk
+        self._method = method
+        self._interceptor = interceptor
+
+    def __call__(self,
+                 request_iterator,
+                 timeout=None,
+                 metadata=None,
+                 credentials=None):
+
+        def continuation(client_call_details, request_iterator):
+            return self._thunk(client_call_details.method)(
+                request_iterator,
+                timeout=client_call_details.timeout,
+                metadata=client_call_details.metadata,
+                credentials=client_call_details.credentials)
+
+        client_call_details = _ClientCallDetails(self._method, timeout,
+                                                 metadata, credentials)
+
+        try:
+            return self._interceptor.intercept_stream_stream(
+                continuation, client_call_details, request_iterator)
+        except Exception as exception:  # pylint:disable=broad-except
+            return _LocalFailure(exception, sys.exc_info()[2])
+
+
+class _Channel(grpc.Channel):
+
+    def __init__(self, channel, interceptor):
+        self._channel = channel
+        self._interceptor = interceptor
+
+    def subscribe(self, *args, **kwargs):
+        self._channel.subscribe(*args, **kwargs)
+
+    def unsubscribe(self, *args, **kwargs):
+        self._channel.unsubscribe(*args, **kwargs)
+
+    def unary_unary(self,
+                    method,
+                    request_serializer=None,
+                    response_deserializer=None):
+        thunk = lambda m: self._channel.unary_unary(m, request_serializer, response_deserializer)
+        if isinstance(self._interceptor, grpc.UnaryUnaryClientInterceptor):
+            return _UnaryUnaryMultiCallable(thunk, method, self._interceptor)
+        else:
+            return thunk(method)
+
+    def unary_stream(self,
+                     method,
+                     request_serializer=None,
+                     response_deserializer=None):
+        thunk = lambda m: self._channel.unary_stream(m, request_serializer, response_deserializer)
+        if isinstance(self._interceptor, grpc.UnaryStreamClientInterceptor):
+            return _UnaryStreamMultiCallable(thunk, method, self._interceptor)
+        else:
+            return thunk(method)
+
+    def stream_unary(self,
+                     method,
+                     request_serializer=None,
+                     response_deserializer=None):
+        thunk = lambda m: self._channel.stream_unary(m, request_serializer, response_deserializer)
+        if isinstance(self._interceptor, grpc.StreamUnaryClientInterceptor):
+            return _StreamUnaryMultiCallable(thunk, method, self._interceptor)
+        else:
+            return thunk(method)
+
+    def stream_stream(self,
+                      method,
+                      request_serializer=None,
+                      response_deserializer=None):
+        thunk = lambda m: self._channel.stream_stream(m, request_serializer, response_deserializer)
+        if isinstance(self._interceptor, grpc.StreamStreamClientInterceptor):
+            return _StreamStreamMultiCallable(thunk, method, self._interceptor)
+        else:
+            return thunk(method)
+
+
+def intercept_channel(channel, *interceptors):
+    for interceptor in reversed(list(interceptors)):
+        if not isinstance(interceptor, grpc.UnaryUnaryClientInterceptor) and \
+           not isinstance(interceptor, grpc.UnaryStreamClientInterceptor) and \
+           not isinstance(interceptor, grpc.StreamUnaryClientInterceptor) and \
+           not isinstance(interceptor, grpc.StreamStreamClientInterceptor):
+            raise TypeError('interceptor must be '
+                            'grpc.UnaryUnaryClientInterceptor or '
+                            'grpc.UnaryStreamClientInterceptor or '
+                            'grpc.StreamUnaryClientInterceptor or '
+                            'grpc.StreamStreamClientInterceptor or ')
+        channel = _Channel(channel, interceptor)
+    return channel
diff --git a/src/python/grpcio/grpc/_server.py b/src/python/grpcio/grpc/_server.py
index 7b78a8b..eec31bd 100644
--- a/src/python/grpcio/grpc/_server.py
+++ b/src/python/grpcio/grpc/_server.py
@@ -23,6 +23,7 @@
 
 import grpc
 from grpc import _common
+from grpc import _interceptor
 from grpc._cython import cygrpc
 from grpc.framework.foundation import callable_util
 
@@ -49,7 +50,7 @@
 
 
 def _serialized_request(request_event):
-    return request_event.batch_operations[0].received_message.bytes()
+    return request_event.batch_operations[0].message()
 
 
 def _application_code(code):
@@ -129,13 +130,13 @@
         effective_code = _abortion_code(state, code)
         effective_details = details if state.details is None else state.details
         if state.initial_metadata_allowed:
-            operations = (cygrpc.operation_send_initial_metadata(
-                (), _EMPTY_FLAGS), cygrpc.operation_send_status_from_server(
+            operations = (cygrpc.SendInitialMetadataOperation(
+                None, _EMPTY_FLAGS), cygrpc.SendStatusFromServerOperation(
                     state.trailing_metadata, effective_code, effective_details,
                     _EMPTY_FLAGS),)
             token = _SEND_INITIAL_METADATA_AND_SEND_STATUS_FROM_SERVER_TOKEN
         else:
-            operations = (cygrpc.operation_send_status_from_server(
+            operations = (cygrpc.SendStatusFromServerOperation(
                 state.trailing_metadata, effective_code, effective_details,
                 _EMPTY_FLAGS),)
             token = _SEND_STATUS_FROM_SERVER_TOKEN
@@ -149,8 +150,7 @@
 
     def receive_close_on_server(receive_close_on_server_event):
         with state.condition:
-            if receive_close_on_server_event.batch_operations[
-                    0].received_cancelled:
+            if receive_close_on_server_event.batch_operations[0].cancelled():
                 state.client = _CANCELLED
             elif state.client is _OPEN:
                 state.client = _CLOSED
@@ -261,7 +261,7 @@
                 _raise_rpc_error(self._state)
             else:
                 if self._state.initial_metadata_allowed:
-                    operation = cygrpc.operation_send_initial_metadata(
+                    operation = cygrpc.SendInitialMetadataOperation(
                         initial_metadata, _EMPTY_FLAGS)
                     self._rpc_event.operation_call.start_server_batch(
                         (operation,), _send_initial_metadata(self._state))
@@ -304,7 +304,7 @@
             raise StopIteration()
         else:
             self._call.start_server_batch(
-                (cygrpc.operation_receive_message(_EMPTY_FLAGS),),
+                (cygrpc.ReceiveMessageOperation(_EMPTY_FLAGS),),
                 _receive_message(self._state, self._call,
                                  self._request_deserializer))
             self._state.due.add(_RECEIVE_MESSAGE_TOKEN)
@@ -347,7 +347,7 @@
                 return None
             else:
                 rpc_event.operation_call.start_server_batch(
-                    (cygrpc.operation_receive_message(_EMPTY_FLAGS),),
+                    (cygrpc.ReceiveMessageOperation(_EMPTY_FLAGS),),
                     _receive_message(state, rpc_event.operation_call,
                                      request_deserializer))
                 state.due.add(_RECEIVE_MESSAGE_TOKEN)
@@ -423,14 +423,15 @@
             return False
         else:
             if state.initial_metadata_allowed:
-                operations = (cygrpc.operation_send_initial_metadata(
-                    (), _EMPTY_FLAGS), cygrpc.operation_send_message(
-                        serialized_response, _EMPTY_FLAGS),)
+                operations = (cygrpc.SendInitialMetadataOperation(None,
+                                                                  _EMPTY_FLAGS),
+                              cygrpc.SendMessageOperation(serialized_response,
+                                                          _EMPTY_FLAGS),)
                 state.initial_metadata_allowed = False
                 token = _SEND_INITIAL_METADATA_AND_SEND_MESSAGE_TOKEN
             else:
-                operations = (cygrpc.operation_send_message(serialized_response,
-                                                            _EMPTY_FLAGS),)
+                operations = (cygrpc.SendMessageOperation(serialized_response,
+                                                          _EMPTY_FLAGS),)
                 token = _SEND_MESSAGE_TOKEN
             rpc_event.operation_call.start_server_batch(
                 operations, _send_message(state, token))
@@ -447,16 +448,16 @@
             code = _completion_code(state)
             details = _details(state)
             operations = [
-                cygrpc.operation_send_status_from_server(
+                cygrpc.SendStatusFromServerOperation(
                     state.trailing_metadata, code, details, _EMPTY_FLAGS),
             ]
             if state.initial_metadata_allowed:
                 operations.append(
-                    cygrpc.operation_send_initial_metadata((), _EMPTY_FLAGS))
+                    cygrpc.SendInitialMetadataOperation(None, _EMPTY_FLAGS))
             if serialized_response is not None:
                 operations.append(
-                    cygrpc.operation_send_message(serialized_response,
-                                                  _EMPTY_FLAGS))
+                    cygrpc.SendMessageOperation(serialized_response,
+                                                _EMPTY_FLAGS))
             rpc_event.operation_call.start_server_batch(
                 operations,
                 _send_status_from_server(state, _SEND_STATUS_FROM_SERVER_TOKEN))
@@ -541,23 +542,31 @@
         method_handler.request_deserializer, method_handler.response_serializer)
 
 
-def _find_method_handler(rpc_event, generic_handlers):
-    for generic_handler in generic_handlers:
-        method_handler = generic_handler.service(
-            _HandlerCallDetails(
-                _common.decode(rpc_event.request_call_details.method),
-                rpc_event.request_metadata))
-        if method_handler is not None:
-            return method_handler
-    else:
+def _find_method_handler(rpc_event, generic_handlers, interceptor_pipeline):
+
+    def query_handlers(handler_call_details):
+        for generic_handler in generic_handlers:
+            method_handler = generic_handler.service(handler_call_details)
+            if method_handler is not None:
+                return method_handler
         return None
 
+    handler_call_details = _HandlerCallDetails(
+        _common.decode(rpc_event.request_call_details.method),
+        rpc_event.request_metadata)
+
+    if interceptor_pipeline is not None:
+        return interceptor_pipeline.execute(query_handlers,
+                                            handler_call_details)
+    else:
+        return query_handlers(handler_call_details)
+
 
 def _reject_rpc(rpc_event, status, details):
-    operations = (cygrpc.operation_send_initial_metadata((), _EMPTY_FLAGS),
-                  cygrpc.operation_receive_close_on_server(_EMPTY_FLAGS),
-                  cygrpc.operation_send_status_from_server((), status, details,
-                                                           _EMPTY_FLAGS),)
+    operations = (cygrpc.SendInitialMetadataOperation(None, _EMPTY_FLAGS),
+                  cygrpc.ReceiveCloseOnServerOperation(_EMPTY_FLAGS),
+                  cygrpc.SendStatusFromServerOperation(None, status, details,
+                                                       _EMPTY_FLAGS),)
     rpc_state = _RPCState()
     rpc_event.operation_call.start_server_batch(
         operations, lambda ignored_event: (rpc_state, (),))
@@ -568,7 +577,7 @@
     state = _RPCState()
     with state.condition:
         rpc_event.operation_call.start_server_batch(
-            (cygrpc.operation_receive_close_on_server(_EMPTY_FLAGS),),
+            (cygrpc.ReceiveCloseOnServerOperation(_EMPTY_FLAGS),),
             _receive_close_on_server(state))
         state.due.add(_RECEIVE_CLOSE_ON_SERVER_TOKEN)
         if method_handler.request_streaming:
@@ -587,13 +596,14 @@
                                                   method_handler, thread_pool)
 
 
-def _handle_call(rpc_event, generic_handlers, thread_pool,
+def _handle_call(rpc_event, generic_handlers, interceptor_pipeline, thread_pool,
                  concurrency_exceeded):
     if not rpc_event.success:
         return None, None
     if rpc_event.request_call_details.method is not None:
         try:
-            method_handler = _find_method_handler(rpc_event, generic_handlers)
+            method_handler = _find_method_handler(rpc_event, generic_handlers,
+                                                  interceptor_pipeline)
         except Exception as exception:  # pylint: disable=broad-except
             details = 'Exception servicing handler: {}'.format(exception)
             logging.exception(details)
@@ -621,12 +631,14 @@
 
 class _ServerState(object):
 
-    def __init__(self, completion_queue, server, generic_handlers, thread_pool,
-                 maximum_concurrent_rpcs):
-        self.lock = threading.Lock()
+    # pylint: disable=too-many-arguments
+    def __init__(self, completion_queue, server, generic_handlers,
+                 interceptor_pipeline, thread_pool, maximum_concurrent_rpcs):
+        self.lock = threading.RLock()
         self.completion_queue = completion_queue
         self.server = server
         self.generic_handlers = list(generic_handlers)
+        self.interceptor_pipeline = interceptor_pipeline
         self.thread_pool = thread_pool
         self.stage = _ServerStage.STOPPED
         self.shutdown_events = None
@@ -691,8 +703,8 @@
                     state.maximum_concurrent_rpcs is not None and
                     state.active_rpc_count >= state.maximum_concurrent_rpcs)
                 rpc_state, rpc_future = _handle_call(
-                    event, state.generic_handlers, state.thread_pool,
-                    concurrency_exceeded)
+                    event, state.generic_handlers, state.interceptor_pipeline,
+                    state.thread_pool, concurrency_exceeded)
                 if rpc_state is not None:
                     state.rpc_states.add(rpc_state)
                 if rpc_future is not None:
@@ -735,22 +747,12 @@
             state.shutdown_events.append(shutdown_event)
             if grace is None:
                 state.server.cancel_all_calls()
-                # TODO(https://github.com/grpc/grpc/issues/6597): delete this loop.
-                for rpc_state in state.rpc_states:
-                    with rpc_state.condition:
-                        rpc_state.client = _CANCELLED
-                        rpc_state.condition.notify_all()
             else:
 
                 def cancel_all_calls_after_grace():
                     shutdown_event.wait(timeout=grace)
                     with state.lock:
                         state.server.cancel_all_calls()
-                        # TODO(https://github.com/grpc/grpc/issues/6597): delete this loop.
-                        for rpc_state in state.rpc_states:
-                            with rpc_state.condition:
-                                rpc_state.client = _CANCELLED
-                                rpc_state.condition.notify_all()
 
                 thread = threading.Thread(target=cancel_all_calls_after_grace)
                 thread.start()
@@ -780,12 +782,14 @@
 
 class Server(grpc.Server):
 
-    def __init__(self, thread_pool, generic_handlers, options,
+    # pylint: disable=too-many-arguments
+    def __init__(self, thread_pool, generic_handlers, interceptors, options,
                  maximum_concurrent_rpcs):
         completion_queue = cygrpc.CompletionQueue()
         server = cygrpc.Server(_common.channel_args(options))
         server.register_completion_queue(completion_queue)
         self._state = _ServerState(completion_queue, server, generic_handlers,
+                                   _interceptor.service_pipeline(interceptors),
                                    thread_pool, maximum_concurrent_rpcs)
 
     def add_generic_rpc_handlers(self, generic_rpc_handlers):
diff --git a/src/python/grpcio/grpc_version.py b/src/python/grpcio/grpc_version.py
index d65b63e..448031a 100644
--- a/src/python/grpcio/grpc_version.py
+++ b/src/python/grpcio/grpc_version.py
@@ -14,4 +14,4 @@
 
 # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio/grpc_version.py.template`!!!
 
-VERSION='1.8.0rc2'
+VERSION='1.8.2'
diff --git a/src/python/grpcio_health_checking/grpc_version.py b/src/python/grpcio_health_checking/grpc_version.py
index 7399e3a..a5ca41a 100644
--- a/src/python/grpcio_health_checking/grpc_version.py
+++ b/src/python/grpcio_health_checking/grpc_version.py
@@ -14,4 +14,4 @@
 
 # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_health_checking/grpc_version.py.template`!!!
 
-VERSION='1.8.0rc2'
+VERSION='1.8.2'
diff --git a/src/python/grpcio_reflection/grpc_version.py b/src/python/grpcio_reflection/grpc_version.py
index 68d281c..0595258 100644
--- a/src/python/grpcio_reflection/grpc_version.py
+++ b/src/python/grpcio_reflection/grpc_version.py
@@ -14,4 +14,4 @@
 
 # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_reflection/grpc_version.py.template`!!!
 
-VERSION='1.8.0rc2'
+VERSION='1.8.2'
diff --git a/src/python/grpcio_testing/grpc_version.py b/src/python/grpcio_testing/grpc_version.py
index 7c60bbf..eec00c0 100644
--- a/src/python/grpcio_testing/grpc_version.py
+++ b/src/python/grpcio_testing/grpc_version.py
@@ -14,4 +14,4 @@
 
 # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_testing/grpc_version.py.template`!!!
 
-VERSION='1.8.0rc2'
+VERSION='1.8.2'
diff --git a/src/python/grpcio_tests/grpc_version.py b/src/python/grpcio_tests/grpc_version.py
index 6c8fb62..aef18d5 100644
--- a/src/python/grpcio_tests/grpc_version.py
+++ b/src/python/grpcio_tests/grpc_version.py
@@ -14,4 +14,4 @@
 
 # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_tests/grpc_version.py.template`!!!
 
-VERSION='1.8.0rc2'
+VERSION='1.8.2'
diff --git a/src/python/grpcio_tests/tests/tests.json b/src/python/grpcio_tests/tests/tests.json
index 34cbade..e033c10 100644
--- a/src/python/grpcio_tests/tests/tests.json
+++ b/src/python/grpcio_tests/tests/tests.json
@@ -34,11 +34,13 @@
   "unit._cython._no_messages_server_completion_queue_per_call_test.Test",
   "unit._cython._no_messages_single_server_completion_queue_test.Test",
   "unit._cython._read_some_but_not_all_responses_test.ReadSomeButNotAllResponsesTest",
+  "unit._cython._server_test.Test",
   "unit._cython.cygrpc_test.InsecureServerInsecureClient",
   "unit._cython.cygrpc_test.SecureServerSecureClient",
   "unit._cython.cygrpc_test.TypeSmokeTest",
   "unit._empty_message_test.EmptyMessageTest",
   "unit._exit_test.ExitTest",
+  "unit._interceptor_test.InterceptorTest",
   "unit._invalid_metadata_test.InvalidMetadataTest",
   "unit._invocation_defects_test.InvocationDefectsTest",
   "unit._metadata_code_details_test.MetadataCodeDetailsTest",
diff --git a/src/python/grpcio_tests/tests/unit/_api_test.py b/src/python/grpcio_tests/tests/unit/_api_test.py
index b14e8d5..d6f4447 100644
--- a/src/python/grpcio_tests/tests/unit/_api_test.py
+++ b/src/python/grpcio_tests/tests/unit/_api_test.py
@@ -33,18 +33,21 @@
             'AuthMetadataPlugin', 'ServerCertificateConfiguration',
             'ServerCredentials', 'UnaryUnaryMultiCallable',
             'UnaryStreamMultiCallable', 'StreamUnaryMultiCallable',
-            'StreamStreamMultiCallable', 'Channel', 'ServicerContext',
+            'StreamStreamMultiCallable', 'UnaryUnaryClientInterceptor',
+            'UnaryStreamClientInterceptor', 'StreamUnaryClientInterceptor',
+            'StreamStreamClientInterceptor', 'Channel', 'ServicerContext',
             'RpcMethodHandler', 'HandlerCallDetails', 'GenericRpcHandler',
-            'ServiceRpcHandler', 'Server', 'unary_unary_rpc_method_handler',
-            'unary_stream_rpc_method_handler',
-            'stream_unary_rpc_method_handler',
+            'ServiceRpcHandler', 'Server', 'ServerInterceptor',
+            'unary_unary_rpc_method_handler', 'unary_stream_rpc_method_handler',
+            'stream_unary_rpc_method_handler', 'ClientCallDetails',
             'stream_stream_rpc_method_handler',
             'method_handlers_generic_handler', 'ssl_channel_credentials',
             'metadata_call_credentials', 'access_token_call_credentials',
             'composite_call_credentials', 'composite_channel_credentials',
             'ssl_server_credentials', 'ssl_server_certificate_configuration',
             'dynamic_ssl_server_credentials', 'channel_ready_future',
-            'insecure_channel', 'secure_channel', 'server',)
+            'insecure_channel', 'secure_channel', 'intercept_channel',
+            'server',)
 
         six.assertCountEqual(self, expected_grpc_code_elements,
                              _from_grpc_import_star.GRPC_ELEMENTS)
diff --git a/src/python/grpcio_tests/tests/unit/_cython/_cancel_many_calls_test.py b/src/python/grpcio_tests/tests/unit/_cython/_cancel_many_calls_test.py
index a8a7175..458b4fe 100644
--- a/src/python/grpcio_tests/tests/unit/_cython/_cancel_many_calls_test.py
+++ b/src/python/grpcio_tests/tests/unit/_cython/_cancel_many_calls_test.py
@@ -65,10 +65,10 @@
 
         with self._lock:
             self._call.start_server_batch(
-                (cygrpc.operation_receive_close_on_server(_EMPTY_FLAGS),),
+                (cygrpc.ReceiveCloseOnServerOperation(_EMPTY_FLAGS),),
                 _RECEIVE_CLOSE_ON_SERVER_TAG)
             self._call.start_server_batch(
-                (cygrpc.operation_receive_message(_EMPTY_FLAGS),),
+                (cygrpc.ReceiveMessageOperation(_EMPTY_FLAGS),),
                 _RECEIVE_MESSAGE_TAG)
         first_event = self._completion_queue.poll()
         if _is_cancellation_event(first_event):
@@ -76,10 +76,10 @@
         else:
             with self._lock:
                 operations = (
-                    cygrpc.operation_send_initial_metadata(_EMPTY_METADATA,
-                                                           _EMPTY_FLAGS),
-                    cygrpc.operation_send_message(b'\x79\x57', _EMPTY_FLAGS),
-                    cygrpc.operation_send_status_from_server(
+                    cygrpc.SendInitialMetadataOperation(_EMPTY_METADATA,
+                                                        _EMPTY_FLAGS),
+                    cygrpc.SendMessageOperation(b'\x79\x57', _EMPTY_FLAGS),
+                    cygrpc.SendStatusFromServerOperation(
                         _EMPTY_METADATA, cygrpc.StatusCode.ok, b'test details!',
                         _EMPTY_FLAGS),)
                 self._call.start_server_batch(operations,
@@ -169,13 +169,13 @@
                     None, _EMPTY_FLAGS, client_completion_queue, b'/twinkies',
                     None, _INFINITE_FUTURE)
                 operations = (
-                    cygrpc.operation_send_initial_metadata(_EMPTY_METADATA,
-                                                           _EMPTY_FLAGS),
-                    cygrpc.operation_send_message(b'\x45\x56', _EMPTY_FLAGS),
-                    cygrpc.operation_send_close_from_client(_EMPTY_FLAGS),
-                    cygrpc.operation_receive_initial_metadata(_EMPTY_FLAGS),
-                    cygrpc.operation_receive_message(_EMPTY_FLAGS),
-                    cygrpc.operation_receive_status_on_client(_EMPTY_FLAGS),)
+                    cygrpc.SendInitialMetadataOperation(_EMPTY_METADATA,
+                                                        _EMPTY_FLAGS),
+                    cygrpc.SendMessageOperation(b'\x45\x56', _EMPTY_FLAGS),
+                    cygrpc.SendCloseFromClientOperation(_EMPTY_FLAGS),
+                    cygrpc.ReceiveInitialMetadataOperation(_EMPTY_FLAGS),
+                    cygrpc.ReceiveMessageOperation(_EMPTY_FLAGS),
+                    cygrpc.ReceiveStatusOnClientOperation(_EMPTY_FLAGS),)
                 tag = 'client_complete_call_{0:04d}_tag'.format(index)
                 client_call.start_client_batch(operations, tag)
                 client_due.add(tag)
diff --git a/src/python/grpcio_tests/tests/unit/_cython/_no_messages_server_completion_queue_per_call_test.py b/src/python/grpcio_tests/tests/unit/_cython/_no_messages_server_completion_queue_per_call_test.py
index d08003a..41291cc 100644
--- a/src/python/grpcio_tests/tests/unit/_cython/_no_messages_server_completion_queue_per_call_test.py
+++ b/src/python/grpcio_tests/tests/unit/_cython/_no_messages_server_completion_queue_per_call_test.py
@@ -49,18 +49,19 @@
         with self.client_condition:
             client_receive_initial_metadata_start_batch_result = (
                 client_call.start_client_batch([
-                    cygrpc.operation_receive_initial_metadata(
-                        _common.EMPTY_FLAGS),
+                    cygrpc.ReceiveInitialMetadataOperation(_common.EMPTY_FLAGS),
                 ], client_receive_initial_metadata_tag))
+            self.assertEqual(cygrpc.CallError.ok,
+                             client_receive_initial_metadata_start_batch_result)
             client_complete_rpc_start_batch_result = client_call.start_client_batch(
                 [
-                    cygrpc.operation_send_initial_metadata(
+                    cygrpc.SendInitialMetadataOperation(
                         _common.INVOCATION_METADATA, _common.EMPTY_FLAGS),
-                    cygrpc.operation_send_close_from_client(
-                        _common.EMPTY_FLAGS),
-                    cygrpc.operation_receive_status_on_client(
-                        _common.EMPTY_FLAGS),
+                    cygrpc.SendCloseFromClientOperation(_common.EMPTY_FLAGS),
+                    cygrpc.ReceiveStatusOnClientOperation(_common.EMPTY_FLAGS),
                 ], client_complete_rpc_tag)
+            self.assertEqual(cygrpc.CallError.ok,
+                             client_complete_rpc_start_batch_result)
             self.client_driver.add_due({
                 client_receive_initial_metadata_tag,
                 client_complete_rpc_tag,
@@ -72,7 +73,7 @@
         with server_call_condition:
             server_send_initial_metadata_start_batch_result = (
                 server_request_call_event.operation_call.start_server_batch([
-                    cygrpc.operation_send_initial_metadata(
+                    cygrpc.SendInitialMetadataOperation(
                         _common.INITIAL_METADATA, _common.EMPTY_FLAGS),
                 ], server_send_initial_metadata_tag))
             server_call_driver.add_due({
@@ -84,9 +85,8 @@
         with server_call_condition:
             server_complete_rpc_start_batch_result = (
                 server_request_call_event.operation_call.start_server_batch([
-                    cygrpc.operation_receive_close_on_server(
-                        _common.EMPTY_FLAGS),
-                    cygrpc.operation_send_status_from_server(
+                    cygrpc.ReceiveCloseOnServerOperation(_common.EMPTY_FLAGS),
+                    cygrpc.SendStatusFromServerOperation(
                         _common.TRAILING_METADATA, cygrpc.StatusCode.ok,
                         b'test details', _common.EMPTY_FLAGS),
                 ], server_complete_rpc_tag))
diff --git a/src/python/grpcio_tests/tests/unit/_cython/_no_messages_single_server_completion_queue_test.py b/src/python/grpcio_tests/tests/unit/_cython/_no_messages_single_server_completion_queue_test.py
index d0166a2..b429a20 100644
--- a/src/python/grpcio_tests/tests/unit/_cython/_no_messages_single_server_completion_queue_test.py
+++ b/src/python/grpcio_tests/tests/unit/_cython/_no_messages_single_server_completion_queue_test.py
@@ -44,17 +44,14 @@
         with self.client_condition:
             client_receive_initial_metadata_start_batch_result = (
                 client_call.start_client_batch([
-                    cygrpc.operation_receive_initial_metadata(
-                        _common.EMPTY_FLAGS),
+                    cygrpc.ReceiveInitialMetadataOperation(_common.EMPTY_FLAGS),
                 ], client_receive_initial_metadata_tag))
             client_complete_rpc_start_batch_result = client_call.start_client_batch(
                 [
-                    cygrpc.operation_send_initial_metadata(
+                    cygrpc.SendInitialMetadataOperation(
                         _common.INVOCATION_METADATA, _common.EMPTY_FLAGS),
-                    cygrpc.operation_send_close_from_client(
-                        _common.EMPTY_FLAGS),
-                    cygrpc.operation_receive_status_on_client(
-                        _common.EMPTY_FLAGS),
+                    cygrpc.SendCloseFromClientOperation(_common.EMPTY_FLAGS),
+                    cygrpc.ReceiveStatusOnClientOperation(_common.EMPTY_FLAGS),
                 ], client_complete_rpc_tag)
             self.client_driver.add_due({
                 client_receive_initial_metadata_tag,
@@ -67,7 +64,7 @@
         with self.server_condition:
             server_send_initial_metadata_start_batch_result = (
                 server_request_call_event.operation_call.start_server_batch([
-                    cygrpc.operation_send_initial_metadata(
+                    cygrpc.SendInitialMetadataOperation(
                         _common.INITIAL_METADATA, _common.EMPTY_FLAGS),
                 ], server_send_initial_metadata_tag))
             self.server_driver.add_due({
@@ -79,11 +76,10 @@
         with self.server_condition:
             server_complete_rpc_start_batch_result = (
                 server_request_call_event.operation_call.start_server_batch([
-                    cygrpc.operation_receive_close_on_server(
-                        _common.EMPTY_FLAGS),
-                    cygrpc.operation_send_status_from_server(
+                    cygrpc.ReceiveCloseOnServerOperation(_common.EMPTY_FLAGS),
+                    cygrpc.SendStatusFromServerOperation(
                         _common.TRAILING_METADATA, cygrpc.StatusCode.ok,
-                        b'test details', _common.EMPTY_FLAGS),
+                        'test details', _common.EMPTY_FLAGS),
                 ], server_complete_rpc_tag))
             self.server_driver.add_due({
                 server_complete_rpc_tag,
diff --git a/src/python/grpcio_tests/tests/unit/_cython/_read_some_but_not_all_responses_test.py b/src/python/grpcio_tests/tests/unit/_cython/_read_some_but_not_all_responses_test.py
index 1deb15b..a6d92f2 100644
--- a/src/python/grpcio_tests/tests/unit/_cython/_read_some_but_not_all_responses_test.py
+++ b/src/python/grpcio_tests/tests/unit/_cython/_read_some_but_not_all_responses_test.py
@@ -158,15 +158,15 @@
         with client_condition:
             client_receive_initial_metadata_start_batch_result = (
                 client_call.start_client_batch([
-                    cygrpc.operation_receive_initial_metadata(_EMPTY_FLAGS),
+                    cygrpc.ReceiveInitialMetadataOperation(_EMPTY_FLAGS),
                 ], client_receive_initial_metadata_tag))
             client_due.add(client_receive_initial_metadata_tag)
             client_complete_rpc_start_batch_result = (
                 client_call.start_client_batch([
-                    cygrpc.operation_send_initial_metadata(_EMPTY_METADATA,
-                                                           _EMPTY_FLAGS),
-                    cygrpc.operation_send_close_from_client(_EMPTY_FLAGS),
-                    cygrpc.operation_receive_status_on_client(_EMPTY_FLAGS),
+                    cygrpc.SendInitialMetadataOperation(_EMPTY_METADATA,
+                                                        _EMPTY_FLAGS),
+                    cygrpc.SendCloseFromClientOperation(_EMPTY_FLAGS),
+                    cygrpc.ReceiveStatusOnClientOperation(_EMPTY_FLAGS),
                 ], client_complete_rpc_tag))
             client_due.add(client_complete_rpc_tag)
 
@@ -175,12 +175,12 @@
         with server_call_condition:
             server_send_initial_metadata_start_batch_result = (
                 server_rpc_event.operation_call.start_server_batch([
-                    cygrpc.operation_send_initial_metadata(_EMPTY_METADATA,
-                                                           _EMPTY_FLAGS),
+                    cygrpc.SendInitialMetadataOperation(_EMPTY_METADATA,
+                                                        _EMPTY_FLAGS),
                 ], server_send_initial_metadata_tag))
             server_send_first_message_start_batch_result = (
                 server_rpc_event.operation_call.start_server_batch([
-                    cygrpc.operation_send_message(b'\x07', _EMPTY_FLAGS),
+                    cygrpc.SendMessageOperation(b'\x07', _EMPTY_FLAGS),
                 ], server_send_first_message_tag))
         server_send_initial_metadata_event = server_call_driver.event_with_tag(
             server_send_initial_metadata_tag)
@@ -189,12 +189,12 @@
         with server_call_condition:
             server_send_second_message_start_batch_result = (
                 server_rpc_event.operation_call.start_server_batch([
-                    cygrpc.operation_send_message(b'\x07', _EMPTY_FLAGS),
+                    cygrpc.SendMessageOperation(b'\x07', _EMPTY_FLAGS),
                 ], server_send_second_message_tag))
             server_complete_rpc_start_batch_result = (
                 server_rpc_event.operation_call.start_server_batch([
-                    cygrpc.operation_receive_close_on_server(_EMPTY_FLAGS),
-                    cygrpc.operation_send_status_from_server(
+                    cygrpc.ReceiveCloseOnServerOperation(_EMPTY_FLAGS),
+                    cygrpc.SendStatusFromServerOperation(
                         (), cygrpc.StatusCode.ok, b'test details',
                         _EMPTY_FLAGS),
                 ], server_complete_rpc_tag))
@@ -208,7 +208,7 @@
             client_receive_first_message_tag = 'client_receive_first_message_tag'
             client_receive_first_message_start_batch_result = (
                 client_call.start_client_batch([
-                    cygrpc.operation_receive_message(_EMPTY_FLAGS),
+                    cygrpc.ReceiveMessageOperation(_EMPTY_FLAGS),
                 ], client_receive_first_message_tag))
             client_due.add(client_receive_first_message_tag)
         client_receive_first_message_event = client_driver.event_with_tag(
diff --git a/src/python/grpcio_tests/tests/unit/_cython/_server_test.py b/src/python/grpcio_tests/tests/unit/_cython/_server_test.py
new file mode 100644
index 0000000..12bf40b
--- /dev/null
+++ b/src/python/grpcio_tests/tests/unit/_cython/_server_test.py
@@ -0,0 +1,49 @@
+# 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.
+"""Test servers at the level of the Cython API."""
+
+import threading
+import time
+import unittest
+
+from grpc._cython import cygrpc
+
+
+class Test(unittest.TestCase):
+
+    def test_lonely_server(self):
+        server_call_completion_queue = cygrpc.CompletionQueue()
+        server_shutdown_completion_queue = cygrpc.CompletionQueue()
+        server = cygrpc.Server(cygrpc.ChannelArgs([]))
+        server.register_completion_queue(server_call_completion_queue)
+        server.register_completion_queue(server_shutdown_completion_queue)
+        port = server.add_http2_port(b'[::]:0')
+        server.start()
+
+        server_request_call_tag = 'server_request_call_tag'
+        server_request_call_start_batch_result = server.request_call(
+            server_call_completion_queue, server_call_completion_queue,
+            server_request_call_tag)
+
+        time.sleep(4)
+
+        server_shutdown_tag = 'server_shutdown_tag'
+        server_shutdown_result = server.shutdown(
+            server_shutdown_completion_queue, server_shutdown_tag)
+        server_request_call_event = server_call_completion_queue.poll()
+        server_shutdown_event = server_shutdown_completion_queue.poll()
+
+
+if __name__ == '__main__':
+    unittest.main(verbosity=2)
diff --git a/src/python/grpcio_tests/tests/unit/_cython/cygrpc_test.py b/src/python/grpcio_tests/tests/unit/_cython/cygrpc_test.py
index 4eda685..002fb9b 100644
--- a/src/python/grpcio_tests/tests/unit/_cython/cygrpc_test.py
+++ b/src/python/grpcio_tests/tests/unit/_cython/cygrpc_test.py
@@ -35,11 +35,6 @@
 
 class TypeSmokeTest(unittest.TestCase):
 
-    def testOperationFlags(self):
-        operation = cygrpc.operation_send_message(b'asdf',
-                                                  cygrpc.WriteFlag.no_compress)
-        self.assertEqual(cygrpc.WriteFlag.no_compress, operation.flags)
-
     def testTimespec(self):
         now = time.time()
         now_timespec_a = cygrpc.Timespec(now)
@@ -170,7 +165,7 @@
         SERVER_TRAILING_METADATA_KEY = 'california_is_in_a_drought'
         SERVER_TRAILING_METADATA_VALUE = 'zomg it is'
         SERVER_STATUS_CODE = cygrpc.StatusCode.ok
-        SERVER_STATUS_DETAILS = b'our work is never over'
+        SERVER_STATUS_DETAILS = 'our work is never over'
         REQUEST = b'in death a member of project mayhem has a name'
         RESPONSE = b'his name is robert paulson'
         METHOD = b'twinkies'
@@ -192,13 +187,13 @@
             (CLIENT_METADATA_ASCII_KEY, CLIENT_METADATA_ASCII_VALUE,),
             (CLIENT_METADATA_BIN_KEY, CLIENT_METADATA_BIN_VALUE,),)
         client_start_batch_result = client_call.start_client_batch([
-            cygrpc.operation_send_initial_metadata(client_initial_metadata,
-                                                   _EMPTY_FLAGS),
-            cygrpc.operation_send_message(REQUEST, _EMPTY_FLAGS),
-            cygrpc.operation_send_close_from_client(_EMPTY_FLAGS),
-            cygrpc.operation_receive_initial_metadata(_EMPTY_FLAGS),
-            cygrpc.operation_receive_message(_EMPTY_FLAGS),
-            cygrpc.operation_receive_status_on_client(_EMPTY_FLAGS)
+            cygrpc.SendInitialMetadataOperation(client_initial_metadata,
+                                                _EMPTY_FLAGS),
+            cygrpc.SendMessageOperation(REQUEST, _EMPTY_FLAGS),
+            cygrpc.SendCloseFromClientOperation(_EMPTY_FLAGS),
+            cygrpc.ReceiveInitialMetadataOperation(_EMPTY_FLAGS),
+            cygrpc.ReceiveMessageOperation(_EMPTY_FLAGS),
+            cygrpc.ReceiveStatusOnClientOperation(_EMPTY_FLAGS),
         ], client_call_tag)
         self.assertEqual(cygrpc.CallError.ok, client_start_batch_result)
         client_event_future = test_utilities.CompletionQueuePollFuture(
@@ -227,12 +222,12 @@
         server_trailing_metadata = (
             (SERVER_TRAILING_METADATA_KEY, SERVER_TRAILING_METADATA_VALUE,),)
         server_start_batch_result = server_call.start_server_batch([
-            cygrpc.operation_send_initial_metadata(
+            cygrpc.SendInitialMetadataOperation(
                 server_initial_metadata,
-                _EMPTY_FLAGS), cygrpc.operation_receive_message(_EMPTY_FLAGS),
-            cygrpc.operation_send_message(RESPONSE, _EMPTY_FLAGS),
-            cygrpc.operation_receive_close_on_server(_EMPTY_FLAGS),
-            cygrpc.operation_send_status_from_server(
+                _EMPTY_FLAGS), cygrpc.ReceiveMessageOperation(_EMPTY_FLAGS),
+            cygrpc.SendMessageOperation(RESPONSE, _EMPTY_FLAGS),
+            cygrpc.ReceiveCloseOnServerOperation(_EMPTY_FLAGS),
+            cygrpc.SendStatusFromServerOperation(
                 server_trailing_metadata, SERVER_STATUS_CODE,
                 SERVER_STATUS_DETAILS, _EMPTY_FLAGS)
         ], server_call_tag)
@@ -245,25 +240,24 @@
         found_client_op_types = set()
         for client_result in client_event.batch_operations:
             # we expect each op type to be unique
-            self.assertNotIn(client_result.type, found_client_op_types)
-            found_client_op_types.add(client_result.type)
-            if client_result.type == cygrpc.OperationType.receive_initial_metadata:
+            self.assertNotIn(client_result.type(), found_client_op_types)
+            found_client_op_types.add(client_result.type())
+            if client_result.type(
+            ) == cygrpc.OperationType.receive_initial_metadata:
                 self.assertTrue(
                     test_common.metadata_transmitted(
                         server_initial_metadata,
-                        client_result.received_metadata))
-            elif client_result.type == cygrpc.OperationType.receive_message:
-                self.assertEqual(RESPONSE,
-                                 client_result.received_message.bytes())
-            elif client_result.type == cygrpc.OperationType.receive_status_on_client:
+                        client_result.initial_metadata()))
+            elif client_result.type() == cygrpc.OperationType.receive_message:
+                self.assertEqual(RESPONSE, client_result.message())
+            elif client_result.type(
+            ) == cygrpc.OperationType.receive_status_on_client:
                 self.assertTrue(
                     test_common.metadata_transmitted(
                         server_trailing_metadata,
-                        client_result.received_metadata))
-                self.assertEqual(SERVER_STATUS_DETAILS,
-                                 client_result.received_status_details)
-                self.assertEqual(SERVER_STATUS_CODE,
-                                 client_result.received_status_code)
+                        client_result.trailing_metadata()))
+                self.assertEqual(SERVER_STATUS_DETAILS, client_result.details())
+                self.assertEqual(SERVER_STATUS_CODE, client_result.code())
         self.assertEqual(
             set([
                 cygrpc.OperationType.send_initial_metadata,
@@ -277,13 +271,13 @@
         self.assertEqual(5, len(server_event.batch_operations))
         found_server_op_types = set()
         for server_result in server_event.batch_operations:
-            self.assertNotIn(client_result.type, found_server_op_types)
-            found_server_op_types.add(server_result.type)
-            if server_result.type == cygrpc.OperationType.receive_message:
-                self.assertEqual(REQUEST,
-                                 server_result.received_message.bytes())
-            elif server_result.type == cygrpc.OperationType.receive_close_on_server:
-                self.assertFalse(server_result.received_cancelled)
+            self.assertNotIn(client_result.type(), found_server_op_types)
+            found_server_op_types.add(server_result.type())
+            if server_result.type() == cygrpc.OperationType.receive_message:
+                self.assertEqual(REQUEST, server_result.message())
+            elif server_result.type(
+            ) == cygrpc.OperationType.receive_close_on_server:
+                self.assertFalse(server_result.cancelled())
         self.assertEqual(
             set([
                 cygrpc.OperationType.send_initial_metadata,
@@ -319,9 +313,8 @@
                                             cygrpc_deadline, description)
 
         client_event_future = perform_client_operations([
-            cygrpc.operation_send_initial_metadata(empty_metadata,
-                                                   _EMPTY_FLAGS),
-            cygrpc.operation_receive_initial_metadata(_EMPTY_FLAGS),
+            cygrpc.SendInitialMetadataOperation(empty_metadata, _EMPTY_FLAGS),
+            cygrpc.ReceiveInitialMetadataOperation(_EMPTY_FLAGS),
         ], "Client prologue")
 
         request_event = self.server_completion_queue.poll(cygrpc_deadline)
@@ -333,8 +326,7 @@
                                             cygrpc_deadline, description)
 
         server_event_future = perform_server_operations([
-            cygrpc.operation_send_initial_metadata(empty_metadata,
-                                                   _EMPTY_FLAGS),
+            cygrpc.SendInitialMetadataOperation(empty_metadata, _EMPTY_FLAGS),
         ], "Server prologue")
 
         client_event_future.result()  # force completion
@@ -343,12 +335,12 @@
         # Messaging
         for _ in range(10):
             client_event_future = perform_client_operations([
-                cygrpc.operation_send_message(b'', _EMPTY_FLAGS),
-                cygrpc.operation_receive_message(_EMPTY_FLAGS),
+                cygrpc.SendMessageOperation(b'', _EMPTY_FLAGS),
+                cygrpc.ReceiveMessageOperation(_EMPTY_FLAGS),
             ], "Client message")
             server_event_future = perform_server_operations([
-                cygrpc.operation_send_message(b'', _EMPTY_FLAGS),
-                cygrpc.operation_receive_message(_EMPTY_FLAGS),
+                cygrpc.SendMessageOperation(b'', _EMPTY_FLAGS),
+                cygrpc.ReceiveMessageOperation(_EMPTY_FLAGS),
             ], "Server receive")
 
             client_event_future.result()  # force completion
@@ -356,13 +348,13 @@
 
         # Epilogue
         client_event_future = perform_client_operations([
-            cygrpc.operation_send_close_from_client(_EMPTY_FLAGS),
-            cygrpc.operation_receive_status_on_client(_EMPTY_FLAGS)
+            cygrpc.SendCloseFromClientOperation(_EMPTY_FLAGS),
+            cygrpc.ReceiveStatusOnClientOperation(_EMPTY_FLAGS)
         ], "Client epilogue")
 
         server_event_future = perform_server_operations([
-            cygrpc.operation_receive_close_on_server(_EMPTY_FLAGS),
-            cygrpc.operation_send_status_from_server(
+            cygrpc.ReceiveCloseOnServerOperation(_EMPTY_FLAGS),
+            cygrpc.SendStatusFromServerOperation(
                 empty_metadata, cygrpc.StatusCode.ok, b'', _EMPTY_FLAGS)
         ], "Server epilogue")
 
diff --git a/src/python/grpcio_tests/tests/unit/_interceptor_test.py b/src/python/grpcio_tests/tests/unit/_interceptor_test.py
new file mode 100644
index 0000000..cf875ed
--- /dev/null
+++ b/src/python/grpcio_tests/tests/unit/_interceptor_test.py
@@ -0,0 +1,571 @@
+# 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.
+"""Test of gRPC Python interceptors."""
+
+import collections
+import itertools
+import threading
+import unittest
+from concurrent import futures
+
+import grpc
+from grpc.framework.foundation import logging_pool
+
+from tests.unit.framework.common import test_constants
+from tests.unit.framework.common import test_control
+
+_SERIALIZE_REQUEST = lambda bytestring: bytestring * 2
+_DESERIALIZE_REQUEST = lambda bytestring: bytestring[len(bytestring) // 2:]
+_SERIALIZE_RESPONSE = lambda bytestring: bytestring * 3
+_DESERIALIZE_RESPONSE = lambda bytestring: bytestring[:len(bytestring) // 3]
+
+_UNARY_UNARY = '/test/UnaryUnary'
+_UNARY_STREAM = '/test/UnaryStream'
+_STREAM_UNARY = '/test/StreamUnary'
+_STREAM_STREAM = '/test/StreamStream'
+
+
+class _Callback(object):
+
+    def __init__(self):
+        self._condition = threading.Condition()
+        self._value = None
+        self._called = False
+
+    def __call__(self, value):
+        with self._condition:
+            self._value = value
+            self._called = True
+            self._condition.notify_all()
+
+    def value(self):
+        with self._condition:
+            while not self._called:
+                self._condition.wait()
+            return self._value
+
+
+class _Handler(object):
+
+    def __init__(self, control):
+        self._control = control
+
+    def handle_unary_unary(self, request, servicer_context):
+        self._control.control()
+        if servicer_context is not None:
+            servicer_context.set_trailing_metadata((('testkey', 'testvalue',),))
+        return request
+
+    def handle_unary_stream(self, request, servicer_context):
+        for _ in range(test_constants.STREAM_LENGTH):
+            self._control.control()
+            yield request
+        self._control.control()
+        if servicer_context is not None:
+            servicer_context.set_trailing_metadata((('testkey', 'testvalue',),))
+
+    def handle_stream_unary(self, request_iterator, servicer_context):
+        if servicer_context is not None:
+            servicer_context.invocation_metadata()
+        self._control.control()
+        response_elements = []
+        for request in request_iterator:
+            self._control.control()
+            response_elements.append(request)
+        self._control.control()
+        if servicer_context is not None:
+            servicer_context.set_trailing_metadata((('testkey', 'testvalue',),))
+        return b''.join(response_elements)
+
+    def handle_stream_stream(self, request_iterator, servicer_context):
+        self._control.control()
+        if servicer_context is not None:
+            servicer_context.set_trailing_metadata((('testkey', 'testvalue',),))
+        for request in request_iterator:
+            self._control.control()
+            yield request
+        self._control.control()
+
+
+class _MethodHandler(grpc.RpcMethodHandler):
+
+    def __init__(self, request_streaming, response_streaming,
+                 request_deserializer, response_serializer, unary_unary,
+                 unary_stream, stream_unary, stream_stream):
+        self.request_streaming = request_streaming
+        self.response_streaming = response_streaming
+        self.request_deserializer = request_deserializer
+        self.response_serializer = response_serializer
+        self.unary_unary = unary_unary
+        self.unary_stream = unary_stream
+        self.stream_unary = stream_unary
+        self.stream_stream = stream_stream
+
+
+class _GenericHandler(grpc.GenericRpcHandler):
+
+    def __init__(self, handler):
+        self._handler = handler
+
+    def service(self, handler_call_details):
+        if handler_call_details.method == _UNARY_UNARY:
+            return _MethodHandler(False, False, None, None,
+                                  self._handler.handle_unary_unary, None, None,
+                                  None)
+        elif handler_call_details.method == _UNARY_STREAM:
+            return _MethodHandler(False, True, _DESERIALIZE_REQUEST,
+                                  _SERIALIZE_RESPONSE, None,
+                                  self._handler.handle_unary_stream, None, None)
+        elif handler_call_details.method == _STREAM_UNARY:
+            return _MethodHandler(True, False, _DESERIALIZE_REQUEST,
+                                  _SERIALIZE_RESPONSE, None, None,
+                                  self._handler.handle_stream_unary, None)
+        elif handler_call_details.method == _STREAM_STREAM:
+            return _MethodHandler(True, True, None, None, None, None, None,
+                                  self._handler.handle_stream_stream)
+        else:
+            return None
+
+
+def _unary_unary_multi_callable(channel):
+    return channel.unary_unary(_UNARY_UNARY)
+
+
+def _unary_stream_multi_callable(channel):
+    return channel.unary_stream(
+        _UNARY_STREAM,
+        request_serializer=_SERIALIZE_REQUEST,
+        response_deserializer=_DESERIALIZE_RESPONSE)
+
+
+def _stream_unary_multi_callable(channel):
+    return channel.stream_unary(
+        _STREAM_UNARY,
+        request_serializer=_SERIALIZE_REQUEST,
+        response_deserializer=_DESERIALIZE_RESPONSE)
+
+
+def _stream_stream_multi_callable(channel):
+    return channel.stream_stream(_STREAM_STREAM)
+
+
+class _ClientCallDetails(
+        collections.namedtuple('_ClientCallDetails',
+                               ('method', 'timeout', 'metadata',
+                                'credentials')), grpc.ClientCallDetails):
+    pass
+
+
+class _GenericClientInterceptor(
+        grpc.UnaryUnaryClientInterceptor, grpc.UnaryStreamClientInterceptor,
+        grpc.StreamUnaryClientInterceptor, grpc.StreamStreamClientInterceptor):
+
+    def __init__(self, interceptor_function):
+        self._fn = interceptor_function
+
+    def intercept_unary_unary(self, continuation, client_call_details, request):
+        new_details, new_request_iterator, postprocess = self._fn(
+            client_call_details, iter((request,)), False, False)
+        response = continuation(new_details, next(new_request_iterator))
+        return postprocess(response) if postprocess else response
+
+    def intercept_unary_stream(self, continuation, client_call_details,
+                               request):
+        new_details, new_request_iterator, postprocess = self._fn(
+            client_call_details, iter((request,)), False, True)
+        response_it = continuation(new_details, new_request_iterator)
+        return postprocess(response_it) if postprocess else response_it
+
+    def intercept_stream_unary(self, continuation, client_call_details,
+                               request_iterator):
+        new_details, new_request_iterator, postprocess = self._fn(
+            client_call_details, request_iterator, True, False)
+        response = continuation(new_details, next(new_request_iterator))
+        return postprocess(response) if postprocess else response
+
+    def intercept_stream_stream(self, continuation, client_call_details,
+                                request_iterator):
+        new_details, new_request_iterator, postprocess = self._fn(
+            client_call_details, request_iterator, True, True)
+        response_it = continuation(new_details, new_request_iterator)
+        return postprocess(response_it) if postprocess else response_it
+
+
+class _LoggingInterceptor(
+        grpc.ServerInterceptor, grpc.UnaryUnaryClientInterceptor,
+        grpc.UnaryStreamClientInterceptor, grpc.StreamUnaryClientInterceptor,
+        grpc.StreamStreamClientInterceptor):
+
+    def __init__(self, tag, record):
+        self.tag = tag
+        self.record = record
+
+    def intercept_service(self, continuation, handler_call_details):
+        self.record.append(self.tag + ':intercept_service')
+        return continuation(handler_call_details)
+
+    def intercept_unary_unary(self, continuation, client_call_details, request):
+        self.record.append(self.tag + ':intercept_unary_unary')
+        return continuation(client_call_details, request)
+
+    def intercept_unary_stream(self, continuation, client_call_details,
+                               request):
+        self.record.append(self.tag + ':intercept_unary_stream')
+        return continuation(client_call_details, request)
+
+    def intercept_stream_unary(self, continuation, client_call_details,
+                               request_iterator):
+        self.record.append(self.tag + ':intercept_stream_unary')
+        return continuation(client_call_details, request_iterator)
+
+    def intercept_stream_stream(self, continuation, client_call_details,
+                                request_iterator):
+        self.record.append(self.tag + ':intercept_stream_stream')
+        return continuation(client_call_details, request_iterator)
+
+
+class _DefectiveClientInterceptor(grpc.UnaryUnaryClientInterceptor):
+
+    def intercept_unary_unary(self, ignored_continuation,
+                              ignored_client_call_details, ignored_request):
+        raise test_control.Defect()
+
+
+def _wrap_request_iterator_stream_interceptor(wrapper):
+
+    def intercept_call(client_call_details, request_iterator, request_streaming,
+                       ignored_response_streaming):
+        if request_streaming:
+            return client_call_details, wrapper(request_iterator), None
+        else:
+            return client_call_details, request_iterator, None
+
+    return _GenericClientInterceptor(intercept_call)
+
+
+def _append_request_header_interceptor(header, value):
+
+    def intercept_call(client_call_details, request_iterator,
+                       ignored_request_streaming, ignored_response_streaming):
+        metadata = []
+        if client_call_details.metadata:
+            metadata = list(client_call_details.metadata)
+        metadata.append((header, value,))
+        client_call_details = _ClientCallDetails(
+            client_call_details.method, client_call_details.timeout, metadata,
+            client_call_details.credentials)
+        return client_call_details, request_iterator, None
+
+    return _GenericClientInterceptor(intercept_call)
+
+
+class _GenericServerInterceptor(grpc.ServerInterceptor):
+
+    def __init__(self, fn):
+        self._fn = fn
+
+    def intercept_service(self, continuation, handler_call_details):
+        return self._fn(continuation, handler_call_details)
+
+
+def _filter_server_interceptor(condition, interceptor):
+
+    def intercept_service(continuation, handler_call_details):
+        if condition(handler_call_details):
+            return interceptor.intercept_service(continuation,
+                                                 handler_call_details)
+        return continuation(handler_call_details)
+
+    return _GenericServerInterceptor(intercept_service)
+
+
+class InterceptorTest(unittest.TestCase):
+
+    def setUp(self):
+        self._control = test_control.PauseFailControl()
+        self._handler = _Handler(self._control)
+        self._server_pool = logging_pool.pool(test_constants.THREAD_CONCURRENCY)
+
+        self._record = []
+        conditional_interceptor = _filter_server_interceptor(
+            lambda x: ('secret', '42') in x.invocation_metadata,
+            _LoggingInterceptor('s3', self._record))
+
+        self._server = grpc.server(
+            self._server_pool,
+            interceptors=(_LoggingInterceptor('s1', self._record),
+                          conditional_interceptor,
+                          _LoggingInterceptor('s2', self._record),))
+        port = self._server.add_insecure_port('[::]:0')
+        self._server.add_generic_rpc_handlers((_GenericHandler(self._handler),))
+        self._server.start()
+
+        self._channel = grpc.insecure_channel('localhost:%d' % port)
+
+    def tearDown(self):
+        self._server.stop(None)
+        self._server_pool.shutdown(wait=True)
+
+    def testTripleRequestMessagesClientInterceptor(self):
+
+        def triple(request_iterator):
+            while True:
+                try:
+                    item = next(request_iterator)
+                    yield item
+                    yield item
+                    yield item
+                except StopIteration:
+                    break
+
+        interceptor = _wrap_request_iterator_stream_interceptor(triple)
+        channel = grpc.intercept_channel(self._channel, interceptor)
+        requests = tuple(b'\x07\x08'
+                         for _ in range(test_constants.STREAM_LENGTH))
+
+        multi_callable = _stream_stream_multi_callable(channel)
+        response_iterator = multi_callable(
+            iter(requests),
+            metadata=(
+                ('test',
+                 'InterceptedStreamRequestBlockingUnaryResponseWithCall'),))
+
+        responses = tuple(response_iterator)
+        self.assertEqual(len(responses), 3 * test_constants.STREAM_LENGTH)
+
+        multi_callable = _stream_stream_multi_callable(self._channel)
+        response_iterator = multi_callable(
+            iter(requests),
+            metadata=(
+                ('test',
+                 'InterceptedStreamRequestBlockingUnaryResponseWithCall'),))
+
+        responses = tuple(response_iterator)
+        self.assertEqual(len(responses), test_constants.STREAM_LENGTH)
+
+    def testDefectiveClientInterceptor(self):
+        interceptor = _DefectiveClientInterceptor()
+        defective_channel = grpc.intercept_channel(self._channel, interceptor)
+
+        request = b'\x07\x08'
+
+        multi_callable = _unary_unary_multi_callable(defective_channel)
+        call_future = multi_callable.future(
+            request,
+            metadata=(
+                ('test', 'InterceptedUnaryRequestBlockingUnaryResponse'),))
+
+        self.assertIsNotNone(call_future.exception())
+        self.assertEqual(call_future.code(), grpc.StatusCode.INTERNAL)
+
+    def testInterceptedHeaderManipulationWithServerSideVerification(self):
+        request = b'\x07\x08'
+
+        channel = grpc.intercept_channel(
+            self._channel, _append_request_header_interceptor('secret', '42'))
+        channel = grpc.intercept_channel(
+            channel,
+            _LoggingInterceptor('c1', self._record),
+            _LoggingInterceptor('c2', self._record))
+
+        self._record[:] = []
+
+        multi_callable = _unary_unary_multi_callable(channel)
+        multi_callable.with_call(
+            request,
+            metadata=(
+                ('test',
+                 'InterceptedUnaryRequestBlockingUnaryResponseWithCall'),))
+
+        self.assertSequenceEqual(self._record, [
+            'c1:intercept_unary_unary', 'c2:intercept_unary_unary',
+            's1:intercept_service', 's3:intercept_service',
+            's2:intercept_service'
+        ])
+
+    def testInterceptedUnaryRequestBlockingUnaryResponse(self):
+        request = b'\x07\x08'
+
+        self._record[:] = []
+
+        channel = grpc.intercept_channel(
+            self._channel,
+            _LoggingInterceptor('c1', self._record),
+            _LoggingInterceptor('c2', self._record))
+
+        multi_callable = _unary_unary_multi_callable(channel)
+        multi_callable(
+            request,
+            metadata=(
+                ('test', 'InterceptedUnaryRequestBlockingUnaryResponse'),))
+
+        self.assertSequenceEqual(self._record, [
+            'c1:intercept_unary_unary', 'c2:intercept_unary_unary',
+            's1:intercept_service', 's2:intercept_service'
+        ])
+
+    def testInterceptedUnaryRequestBlockingUnaryResponseWithCall(self):
+        request = b'\x07\x08'
+
+        channel = grpc.intercept_channel(
+            self._channel,
+            _LoggingInterceptor('c1', self._record),
+            _LoggingInterceptor('c2', self._record))
+
+        self._record[:] = []
+
+        multi_callable = _unary_unary_multi_callable(channel)
+        multi_callable.with_call(
+            request,
+            metadata=(
+                ('test',
+                 'InterceptedUnaryRequestBlockingUnaryResponseWithCall'),))
+
+        self.assertSequenceEqual(self._record, [
+            'c1:intercept_unary_unary', 'c2:intercept_unary_unary',
+            's1:intercept_service', 's2:intercept_service'
+        ])
+
+    def testInterceptedUnaryRequestFutureUnaryResponse(self):
+        request = b'\x07\x08'
+
+        self._record[:] = []
+        channel = grpc.intercept_channel(
+            self._channel,
+            _LoggingInterceptor('c1', self._record),
+            _LoggingInterceptor('c2', self._record))
+
+        multi_callable = _unary_unary_multi_callable(channel)
+        response_future = multi_callable.future(
+            request,
+            metadata=(('test', 'InterceptedUnaryRequestFutureUnaryResponse'),))
+        response_future.result()
+
+        self.assertSequenceEqual(self._record, [
+            'c1:intercept_unary_unary', 'c2:intercept_unary_unary',
+            's1:intercept_service', 's2:intercept_service'
+        ])
+
+    def testInterceptedUnaryRequestStreamResponse(self):
+        request = b'\x37\x58'
+
+        self._record[:] = []
+        channel = grpc.intercept_channel(
+            self._channel,
+            _LoggingInterceptor('c1', self._record),
+            _LoggingInterceptor('c2', self._record))
+
+        multi_callable = _unary_stream_multi_callable(channel)
+        response_iterator = multi_callable(
+            request,
+            metadata=(('test', 'InterceptedUnaryRequestStreamResponse'),))
+        tuple(response_iterator)
+
+        self.assertSequenceEqual(self._record, [
+            'c1:intercept_unary_stream', 'c2:intercept_unary_stream',
+            's1:intercept_service', 's2:intercept_service'
+        ])
+
+    def testInterceptedStreamRequestBlockingUnaryResponse(self):
+        requests = tuple(b'\x07\x08'
+                         for _ in range(test_constants.STREAM_LENGTH))
+        request_iterator = iter(requests)
+
+        self._record[:] = []
+        channel = grpc.intercept_channel(
+            self._channel,
+            _LoggingInterceptor('c1', self._record),
+            _LoggingInterceptor('c2', self._record))
+
+        multi_callable = _stream_unary_multi_callable(channel)
+        multi_callable(
+            request_iterator,
+            metadata=(
+                ('test', 'InterceptedStreamRequestBlockingUnaryResponse'),))
+
+        self.assertSequenceEqual(self._record, [
+            'c1:intercept_stream_unary', 'c2:intercept_stream_unary',
+            's1:intercept_service', 's2:intercept_service'
+        ])
+
+    def testInterceptedStreamRequestBlockingUnaryResponseWithCall(self):
+        requests = tuple(b'\x07\x08'
+                         for _ in range(test_constants.STREAM_LENGTH))
+        request_iterator = iter(requests)
+
+        self._record[:] = []
+        channel = grpc.intercept_channel(
+            self._channel,
+            _LoggingInterceptor('c1', self._record),
+            _LoggingInterceptor('c2', self._record))
+
+        multi_callable = _stream_unary_multi_callable(channel)
+        multi_callable.with_call(
+            request_iterator,
+            metadata=(
+                ('test',
+                 'InterceptedStreamRequestBlockingUnaryResponseWithCall'),))
+
+        self.assertSequenceEqual(self._record, [
+            'c1:intercept_stream_unary', 'c2:intercept_stream_unary',
+            's1:intercept_service', 's2:intercept_service'
+        ])
+
+    def testInterceptedStreamRequestFutureUnaryResponse(self):
+        requests = tuple(b'\x07\x08'
+                         for _ in range(test_constants.STREAM_LENGTH))
+        request_iterator = iter(requests)
+
+        self._record[:] = []
+        channel = grpc.intercept_channel(
+            self._channel,
+            _LoggingInterceptor('c1', self._record),
+            _LoggingInterceptor('c2', self._record))
+
+        multi_callable = _stream_unary_multi_callable(channel)
+        response_future = multi_callable.future(
+            request_iterator,
+            metadata=(('test', 'InterceptedStreamRequestFutureUnaryResponse'),))
+        response_future.result()
+
+        self.assertSequenceEqual(self._record, [
+            'c1:intercept_stream_unary', 'c2:intercept_stream_unary',
+            's1:intercept_service', 's2:intercept_service'
+        ])
+
+    def testInterceptedStreamRequestStreamResponse(self):
+        requests = tuple(b'\x77\x58'
+                         for _ in range(test_constants.STREAM_LENGTH))
+        request_iterator = iter(requests)
+
+        self._record[:] = []
+        channel = grpc.intercept_channel(
+            self._channel,
+            _LoggingInterceptor('c1', self._record),
+            _LoggingInterceptor('c2', self._record))
+
+        multi_callable = _stream_stream_multi_callable(channel)
+        response_iterator = multi_callable(
+            request_iterator,
+            metadata=(('test', 'InterceptedStreamRequestStreamResponse'),))
+        tuple(response_iterator)
+
+        self.assertSequenceEqual(self._record, [
+            'c1:intercept_stream_stream', 'c2:intercept_stream_stream',
+            's1:intercept_service', 's2:intercept_service'
+        ])
+
+
+if __name__ == '__main__':
+    unittest.main(verbosity=2)
diff --git a/src/python/grpcio_tests/tests/unit/_metadata_test.py b/src/python/grpcio_tests/tests/unit/_metadata_test.py
index 557d527..0669486 100644
--- a/src/python/grpcio_tests/tests/unit/_metadata_test.py
+++ b/src/python/grpcio_tests/tests/unit/_metadata_test.py
@@ -34,16 +34,19 @@
 _STREAM_UNARY = '/test/StreamUnary'
 _STREAM_STREAM = '/test/StreamStream'
 
-_CLIENT_METADATA = (('client-md-key', 'client-md-key'),
-                    ('client-md-key-bin', b'\x00\x01'))
+_INVOCATION_METADATA = ((b'invocation-md-key', u'invocation-md-value',),
+                        (u'invocation-md-key-bin', b'\x00\x01',),)
+_EXPECTED_INVOCATION_METADATA = (('invocation-md-key', 'invocation-md-value',),
+                                 ('invocation-md-key-bin', b'\x00\x01',),)
 
-_SERVER_INITIAL_METADATA = (
-    ('server-initial-md-key', 'server-initial-md-value'),
-    ('server-initial-md-key-bin', b'\x00\x02'))
+_INITIAL_METADATA = ((b'initial-md-key', u'initial-md-value'),
+                     (u'initial-md-key-bin', b'\x00\x02'))
+_EXPECTED_INITIAL_METADATA = (('initial-md-key', 'initial-md-value',),
+                              ('initial-md-key-bin', b'\x00\x02',),)
 
-_SERVER_TRAILING_METADATA = (
-    ('server-trailing-md-key', 'server-trailing-md-value'),
-    ('server-trailing-md-key-bin', b'\x00\x03'))
+_TRAILING_METADATA = (('server-trailing-md-key', 'server-trailing-md-value',),
+                      ('server-trailing-md-key-bin', b'\x00\x03',),)
+_EXPECTED_TRAILING_METADATA = _TRAILING_METADATA
 
 
 def user_agent(metadata):
@@ -56,7 +59,8 @@
 def validate_client_metadata(test, servicer_context):
     test.assertTrue(
         test_common.metadata_transmitted(
-            _CLIENT_METADATA, servicer_context.invocation_metadata()))
+            _EXPECTED_INVOCATION_METADATA,
+            servicer_context.invocation_metadata()))
     test.assertTrue(
         user_agent(servicer_context.invocation_metadata())
         .startswith('primary-agent ' + _channel._USER_AGENT))
@@ -67,23 +71,23 @@
 
 def handle_unary_unary(test, request, servicer_context):
     validate_client_metadata(test, servicer_context)
-    servicer_context.send_initial_metadata(_SERVER_INITIAL_METADATA)
-    servicer_context.set_trailing_metadata(_SERVER_TRAILING_METADATA)
+    servicer_context.send_initial_metadata(_INITIAL_METADATA)
+    servicer_context.set_trailing_metadata(_TRAILING_METADATA)
     return _RESPONSE
 
 
 def handle_unary_stream(test, request, servicer_context):
     validate_client_metadata(test, servicer_context)
-    servicer_context.send_initial_metadata(_SERVER_INITIAL_METADATA)
-    servicer_context.set_trailing_metadata(_SERVER_TRAILING_METADATA)
+    servicer_context.send_initial_metadata(_INITIAL_METADATA)
+    servicer_context.set_trailing_metadata(_TRAILING_METADATA)
     for _ in range(test_constants.STREAM_LENGTH):
         yield _RESPONSE
 
 
 def handle_stream_unary(test, request_iterator, servicer_context):
     validate_client_metadata(test, servicer_context)
-    servicer_context.send_initial_metadata(_SERVER_INITIAL_METADATA)
-    servicer_context.set_trailing_metadata(_SERVER_TRAILING_METADATA)
+    servicer_context.send_initial_metadata(_INITIAL_METADATA)
+    servicer_context.set_trailing_metadata(_TRAILING_METADATA)
     # TODO(issue:#6891) We should be able to remove this loop
     for request in request_iterator:
         pass
@@ -92,8 +96,8 @@
 
 def handle_stream_stream(test, request_iterator, servicer_context):
     validate_client_metadata(test, servicer_context)
-    servicer_context.send_initial_metadata(_SERVER_INITIAL_METADATA)
-    servicer_context.set_trailing_metadata(_SERVER_TRAILING_METADATA)
+    servicer_context.send_initial_metadata(_INITIAL_METADATA)
+    servicer_context.set_trailing_metadata(_TRAILING_METADATA)
     # TODO(issue:#6891) We should be able to remove this loop,
     # and replace with return; yield
     for request in request_iterator:
@@ -156,50 +160,50 @@
     def testUnaryUnary(self):
         multi_callable = self._channel.unary_unary(_UNARY_UNARY)
         unused_response, call = multi_callable.with_call(
-            _REQUEST, metadata=_CLIENT_METADATA)
+            _REQUEST, metadata=_INVOCATION_METADATA)
         self.assertTrue(
-            test_common.metadata_transmitted(_SERVER_INITIAL_METADATA,
+            test_common.metadata_transmitted(_EXPECTED_INITIAL_METADATA,
                                              call.initial_metadata()))
         self.assertTrue(
-            test_common.metadata_transmitted(_SERVER_TRAILING_METADATA,
+            test_common.metadata_transmitted(_EXPECTED_TRAILING_METADATA,
                                              call.trailing_metadata()))
 
     def testUnaryStream(self):
         multi_callable = self._channel.unary_stream(_UNARY_STREAM)
-        call = multi_callable(_REQUEST, metadata=_CLIENT_METADATA)
+        call = multi_callable(_REQUEST, metadata=_INVOCATION_METADATA)
         self.assertTrue(
-            test_common.metadata_transmitted(_SERVER_INITIAL_METADATA,
+            test_common.metadata_transmitted(_EXPECTED_INITIAL_METADATA,
                                              call.initial_metadata()))
         for _ in call:
             pass
         self.assertTrue(
-            test_common.metadata_transmitted(_SERVER_TRAILING_METADATA,
+            test_common.metadata_transmitted(_EXPECTED_TRAILING_METADATA,
                                              call.trailing_metadata()))
 
     def testStreamUnary(self):
         multi_callable = self._channel.stream_unary(_STREAM_UNARY)
         unused_response, call = multi_callable.with_call(
             iter([_REQUEST] * test_constants.STREAM_LENGTH),
-            metadata=_CLIENT_METADATA)
+            metadata=_INVOCATION_METADATA)
         self.assertTrue(
-            test_common.metadata_transmitted(_SERVER_INITIAL_METADATA,
+            test_common.metadata_transmitted(_EXPECTED_INITIAL_METADATA,
                                              call.initial_metadata()))
         self.assertTrue(
-            test_common.metadata_transmitted(_SERVER_TRAILING_METADATA,
+            test_common.metadata_transmitted(_EXPECTED_TRAILING_METADATA,
                                              call.trailing_metadata()))
 
     def testStreamStream(self):
         multi_callable = self._channel.stream_stream(_STREAM_STREAM)
         call = multi_callable(
             iter([_REQUEST] * test_constants.STREAM_LENGTH),
-            metadata=_CLIENT_METADATA)
+            metadata=_INVOCATION_METADATA)
         self.assertTrue(
-            test_common.metadata_transmitted(_SERVER_INITIAL_METADATA,
+            test_common.metadata_transmitted(_EXPECTED_INITIAL_METADATA,
                                              call.initial_metadata()))
         for _ in call:
             pass
         self.assertTrue(
-            test_common.metadata_transmitted(_SERVER_TRAILING_METADATA,
+            test_common.metadata_transmitted(_EXPECTED_TRAILING_METADATA,
                                              call.trailing_metadata()))
 
 
diff --git a/src/ruby/lib/grpc/version.rb b/src/ruby/lib/grpc/version.rb
index f1bb325..13b7b81 100644
--- a/src/ruby/lib/grpc/version.rb
+++ b/src/ruby/lib/grpc/version.rb
@@ -14,5 +14,5 @@
 
 # GRPC contains the General RPC module.
 module GRPC
-  VERSION = '1.8.0.pre2'
+  VERSION = '1.8.2'
 end
diff --git a/src/ruby/tools/version.rb b/src/ruby/tools/version.rb
index 6b4dbf6..e849624 100644
--- a/src/ruby/tools/version.rb
+++ b/src/ruby/tools/version.rb
@@ -14,6 +14,6 @@
 
 module GRPC
   module Tools
-    VERSION = '1.8.0.pre2'
+    VERSION = '1.8.2'
   end
 end
diff --git a/tools/distrib/python/grpcio_tools/grpc_version.py b/tools/distrib/python/grpcio_tools/grpc_version.py
index 2995f6c..e6d7721 100644
--- a/tools/distrib/python/grpcio_tools/grpc_version.py
+++ b/tools/distrib/python/grpcio_tools/grpc_version.py
@@ -14,4 +14,4 @@
 
 # AUTO-GENERATED FROM `$REPO_ROOT/templates/tools/distrib/python/grpcio_tools/grpc_version.py.template`!!!
 
-VERSION='1.8.0rc2'
+VERSION='1.8.2'
diff --git a/tools/doxygen/Doxyfile.c++ b/tools/doxygen/Doxyfile.c++
index 026ec9f..5633cf2 100644
--- a/tools/doxygen/Doxyfile.c++
+++ b/tools/doxygen/Doxyfile.c++
@@ -40,7 +40,7 @@
 # could be handy for archiving the generated documentation or if some version
 # control system is used.
 
-PROJECT_NUMBER         = 1.8.0-pre2
+PROJECT_NUMBER         = 1.8.2
 
 # Using the PROJECT_BRIEF tag one can provide an optional one line description
 # for a project that appears at the top of each page and should give viewer a
diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal
index cba20b3..667005c 100644
--- a/tools/doxygen/Doxyfile.c++.internal
+++ b/tools/doxygen/Doxyfile.c++.internal
@@ -40,7 +40,7 @@
 # could be handy for archiving the generated documentation or if some version
 # control system is used.
 
-PROJECT_NUMBER         = 1.8.0-pre2
+PROJECT_NUMBER         = 1.8.2
 
 # Using the PROJECT_BRIEF tag one can provide an optional one line description
 # for a project that appears at the top of each page and should give viewer a
diff --git a/tools/doxygen/Doxyfile.core b/tools/doxygen/Doxyfile.core
index f6fc748..3c1abad 100644
--- a/tools/doxygen/Doxyfile.core
+++ b/tools/doxygen/Doxyfile.core
@@ -40,7 +40,7 @@
 # could be handy for archiving the generated documentation or if some version
 # control system is used.
 
-PROJECT_NUMBER         = 5.0.0-pre2
+PROJECT_NUMBER         = 5.0.0
 
 # Using the PROJECT_BRIEF tag one can provide an optional one line description
 # for a project that appears at the top of each page and should give viewer a
diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal
index 009cf03..f7d8ba3 100644
--- a/tools/doxygen/Doxyfile.core.internal
+++ b/tools/doxygen/Doxyfile.core.internal
@@ -40,7 +40,7 @@
 # could be handy for archiving the generated documentation or if some version
 # control system is used.
 
-PROJECT_NUMBER         = 5.0.0-pre2
+PROJECT_NUMBER         = 5.0.0
 
 # Using the PROJECT_BRIEF tag one can provide an optional one line description
 # for a project that appears at the top of each page and should give viewer a