Merge pull request #13886 from armchair-philosophy/fix-wire-link-in-web-protocol-doc

Use 'PROTOCOL-HTTP2.md' for reference to 'gRPC over HTTP2' document
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/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/src/core/lib/iomgr/ev_epoll1_linux.cc b/src/core/lib/iomgr/ev_epoll1_linux.cc
index 92b4b8b..1ab7e51 100644
--- a/src/core/lib/iomgr/ev_epoll1_linux.cc
+++ b/src/core/lib/iomgr/ev_epoll1_linux.cc
@@ -1232,8 +1232,6 @@
 /* If GRPC_LINUX_EPOLL is not defined, it means epoll is not available. Return
  * NULL */
 const grpc_event_engine_vtable* grpc_init_epoll1_linux(bool explicit_request) {
-  gpr_log(GPR_ERROR,
-          "Skipping epoll1 because GRPC_LINUX_EPOLL is not defined.");
   return nullptr;
 }
 #endif /* defined(GRPC_POSIX_SOCKET) */
diff --git a/src/core/lib/iomgr/ev_epollex_linux.cc b/src/core/lib/iomgr/ev_epollex_linux.cc
index df2f629..5f5f45a 100644
--- a/src/core/lib/iomgr/ev_epollex_linux.cc
+++ b/src/core/lib/iomgr/ev_epollex_linux.cc
@@ -1449,8 +1449,6 @@
  * NULL */
 const grpc_event_engine_vtable* grpc_init_epollex_linux(
     bool explicitly_requested) {
-  gpr_log(GPR_ERROR,
-          "Skipping epollex because GRPC_LINUX_EPOLL is not defined.");
   return nullptr;
 }
 #endif /* defined(GRPC_POSIX_SOCKET) */
diff --git a/src/core/lib/iomgr/ev_epollsig_linux.cc b/src/core/lib/iomgr/ev_epollsig_linux.cc
index bc548a1..8072a6c 100644
--- a/src/core/lib/iomgr/ev_epollsig_linux.cc
+++ b/src/core/lib/iomgr/ev_epollsig_linux.cc
@@ -1732,8 +1732,6 @@
  * NULL */
 const grpc_event_engine_vtable* grpc_init_epollsig_linux(
     bool explicit_request) {
-  gpr_log(GPR_ERROR,
-          "Skipping epollsig because GRPC_LINUX_EPOLL is not defined.");
   return nullptr;
 }
 #endif /* defined(GRPC_POSIX_SOCKET) */
diff --git a/src/core/lib/iomgr/ev_poll_posix.cc b/src/core/lib/iomgr/ev_poll_posix.cc
index 53de94f..a569f67 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.
@@ -335,6 +336,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;
@@ -950,7 +952,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];
@@ -1017,6 +1020,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(&watchers[i], pfds[i].revents & POLLIN_CHECK,
                         pfds[i].revents & POLLOUT_CHECK, pollset);
           }
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/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/call.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/call.pyx.pxi
index 6361669..0892215 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/call.pyx.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/call.pyx.pxi
@@ -26,16 +26,13 @@
   def _start_batch(self, operations, tag, retain_self):
     if not self.is_valid:
       raise ValueError("invalid call object cannot be used from Python")
-    cdef OperationTag operation_tag = OperationTag(tag, operations)
-    if retain_self:
-      operation_tag.operation_call = self
-    else:
-      operation_tag.operation_call = None
-    operation_tag.store_ops()
-    cpython.Py_INCREF(operation_tag)
+    cdef _BatchOperationTag batch_operation_tag = _BatchOperationTag(
+        tag, operations, self if retain_self else None)
+    batch_operation_tag.prepare()
+    cpython.Py_INCREF(batch_operation_tag)
     return grpc_call_start_batch(
-          self.c_call, operation_tag.c_ops, operation_tag.c_nops,
-          <cpython.PyObject *>operation_tag, NULL)
+          self.c_call, batch_operation_tag.c_ops, batch_operation_tag.c_nops,
+          <cpython.PyObject *>batch_operation_tag, NULL)
 
   def start_client_batch(self, operations, tag):
     # We don't reference this call in the operations tag because
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx.pxi
index 644df67..443d534 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx.pxi
@@ -76,12 +76,12 @@
   def watch_connectivity_state(
       self, grpc_connectivity_state last_observed_state,
       Timespec deadline not None, CompletionQueue queue not None, tag):
-    cdef OperationTag operation_tag = OperationTag(tag, None)
-    cpython.Py_INCREF(operation_tag)
+    cdef _ConnectivityTag connectivity_tag = _ConnectivityTag(tag)
+    cpython.Py_INCREF(connectivity_tag)
     with nogil:
       grpc_channel_watch_connectivity_state(
           self.c_channel, last_observed_state, deadline.c_time,
-          queue.c_completion_queue, <cpython.PyObject *>operation_tag)
+          queue.c_completion_queue, <cpython.PyObject *>connectivity_tag)
 
   def target(self):
     cdef char *target = NULL
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/completion_queue.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/completion_queue.pyx.pxi
index 140fc35..e259789 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/completion_queue.pyx.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/completion_queue.pyx.pxi
@@ -37,42 +37,20 @@
     self.is_shutdown = False
 
   cdef _interpret_event(self, grpc_event event):
-    cdef OperationTag tag = None
-    cdef object user_tag = None
-    cdef Call operation_call = None
-    cdef CallDetails request_call_details = None
-    cdef object request_metadata = None
-    cdef object batch_operations = None
+    cdef _Tag tag = None
     if event.type == GRPC_QUEUE_TIMEOUT:
-      return Event(
-          event.type, False, None, None, None, None, False, None)
+      # NOTE(nathaniel): For now we coopt ConnectivityEvent here.
+      return ConnectivityEvent(GRPC_QUEUE_TIMEOUT, False, None)
     elif event.type == GRPC_QUEUE_SHUTDOWN:
       self.is_shutdown = True
-      return Event(
-          event.type, True, None, None, None, None, False, None)
+      # NOTE(nathaniel): For now we coopt ConnectivityEvent here.
+      return ConnectivityEvent(GRPC_QUEUE_TIMEOUT, True, None)
     else:
-      if event.tag != NULL:
-        tag = <OperationTag>event.tag
-        # We receive event tags only after they've been inc-ref'd elsewhere in
-        # the code.
-        cpython.Py_DECREF(tag)
-        if tag.shutting_down_server is not None:
-          tag.shutting_down_server.notify_shutdown_complete()
-        user_tag = tag.user_tag
-        operation_call = tag.operation_call
-        request_call_details = tag.request_call_details
-        if tag.is_new_request:
-          request_metadata = _metadata(&tag._c_request_metadata)
-          grpc_metadata_array_destroy(&tag._c_request_metadata)
-        batch_operations = tag.release_ops()
-        if tag.is_new_request:
-          # Stuff in the tag not explicitly handled by us needs to live through
-          # the life of the call
-          operation_call.references.extend(tag.references)
-      return Event(
-          event.type, event.success, user_tag, operation_call,
-          request_call_details, request_metadata, tag.is_new_request,
-          batch_operations)
+      tag = <_Tag>event.tag
+      # We receive event tags only after they've been inc-ref'd elsewhere in
+      # the code.
+      cpython.Py_DECREF(tag)
+      return tag.event(event)
 
   def poll(self, Timespec deadline=None):
     # We name this 'poll' to avoid problems with CPython's expectations for
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/event.pxd.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/event.pxd.pxi
new file mode 100644
index 0000000..686199e
--- /dev/null
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/event.pxd.pxi
@@ -0,0 +1,45 @@
+# 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 ConnectivityEvent:
+
+  cdef readonly grpc_completion_type completion_type
+  cdef readonly bint success
+  cdef readonly object tag
+
+
+cdef class RequestCallEvent:
+
+  cdef readonly grpc_completion_type completion_type
+  cdef readonly bint success
+  cdef readonly object tag
+  cdef readonly Call call
+  cdef readonly CallDetails call_details
+  cdef readonly tuple invocation_metadata
+
+
+cdef class BatchOperationEvent:
+
+  cdef readonly grpc_completion_type completion_type
+  cdef readonly bint success
+  cdef readonly object tag
+  cdef readonly object batch_operations
+
+
+cdef class ServerShutdownEvent:
+
+  cdef readonly grpc_completion_type completion_type
+  cdef readonly bint success
+  cdef readonly object tag
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/event.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/event.pyx.pxi
new file mode 100644
index 0000000..af26d27
--- /dev/null
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/event.pyx.pxi
@@ -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.
+
+
+cdef class ConnectivityEvent:
+
+  def __cinit__(
+      self, grpc_completion_type completion_type, bint success, object tag):
+    self.completion_type = completion_type
+    self.success = success
+    self.tag = tag
+
+
+cdef class RequestCallEvent:
+
+  def __cinit__(
+      self, grpc_completion_type completion_type, bint success, object tag,
+      Call call, CallDetails call_details, tuple invocation_metadata):
+    self.completion_type = completion_type
+    self.success = success
+    self.tag = tag
+    self.call = call
+    self.call_details = call_details
+    self.invocation_metadata = invocation_metadata
+
+
+cdef class BatchOperationEvent:
+
+  def __cinit__(
+      self, grpc_completion_type completion_type, bint success, object tag,
+      object batch_operations):
+    self.completion_type = completion_type
+    self.success = success
+    self.tag = tag
+    self.batch_operations = batch_operations
+
+
+cdef class ServerShutdownEvent:
+
+  def __cinit__(
+      self, grpc_completion_type completion_type, bint success, object tag):
+    self.completion_type = completion_type
+    self.success = success
+    self.tag = tag
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi
index 6a72bbf..6ee8336 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
 
@@ -183,6 +185,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
@@ -258,9 +272,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
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..7b2482d 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/records.pxd.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/records.pxd.pxi
@@ -28,48 +28,6 @@
   cdef grpc_call_details c_details
 
 
-cdef class OperationTag:
-
-  cdef object user_tag
-  cdef list references
-  # This allows CompletionQueue to notify the Python Server object that the
-  # underlying GRPC core server has shutdown
-  cdef Server shutting_down_server
-  cdef Call operation_call
-  cdef CallDetails request_call_details
-  cdef grpc_metadata_array _c_request_metadata
-  cdef grpc_op *c_ops
-  cdef size_t c_nops
-  cdef readonly object _operations
-  cdef bint is_new_request
-
-  cdef void store_ops(self)
-  cdef object release_ops(self)
-
-
-cdef class Event:
-
-  cdef readonly grpc_completion_type type
-  cdef readonly bint success
-  cdef readonly object tag
-
-  # For Server.request_call
-  cdef readonly bint is_new_request
-  cdef readonly CallDetails request_call_details
-  cdef readonly object request_metadata
-
-  # For server calls
-  cdef readonly Call operation_call
-
-  # For Call.start_batch
-  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 +47,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 26eaf50..bc2cd03 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx.pxi
@@ -218,111 +218,6 @@
     return timespec
 
 
-cdef class OperationTag:
-
-  def __cinit__(self, user_tag, operations):
-    self.user_tag = user_tag
-    self.references = []
-    self._operations = operations
-
-  cdef void store_ops(self):
-    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
-
-  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]
-      gpr_free(self.c_ops)
-      return self._operations
-    else:
-      return ()
-
-
-cdef class Event:
-
-  def __cinit__(self, grpc_completion_type type, bint success,
-                object tag, Call operation_call,
-                CallDetails request_call_details,
-                object request_metadata,
-                bint is_new_request,
-                object batch_operations):
-    self.type = type
-    self.success = success
-    self.tag = tag
-    self.operation_call = operation_call
-    self.request_call_details = request_call_details
-    self.request_metadata = request_metadata
-    self.batch_operations = batch_operations
-    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):
@@ -407,185 +302,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/server.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/server.pyx.pxi
index f8d7892..c19becc 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/server.pyx.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/server.pyx.pxi
@@ -78,19 +78,15 @@
       raise ValueError("server must be started and not shutting down")
     if server_queue not in self.registered_completion_queues:
       raise ValueError("server_queue must be a registered completion queue")
-    cdef OperationTag operation_tag = OperationTag(tag, None)
-    operation_tag.operation_call = Call()
-    operation_tag.request_call_details = CallDetails()
-    grpc_metadata_array_init(&operation_tag._c_request_metadata)
-    operation_tag.references.extend([self, call_queue, server_queue])
-    operation_tag.is_new_request = True
-    cpython.Py_INCREF(operation_tag)
+    cdef _RequestCallTag request_call_tag = _RequestCallTag(tag)
+    request_call_tag.prepare()
+    cpython.Py_INCREF(request_call_tag)
     return grpc_server_request_call(
-        self.c_server, &operation_tag.operation_call.c_call,
-        &operation_tag.request_call_details.c_details,
-        &operation_tag._c_request_metadata,
+        self.c_server, &request_call_tag.call.c_call,
+        &request_call_tag.call_details.c_details,
+        &request_call_tag.c_invocation_metadata,
         call_queue.c_completion_queue, server_queue.c_completion_queue,
-        <cpython.PyObject *>operation_tag)
+        <cpython.PyObject *>request_call_tag)
 
   def register_completion_queue(
       self, CompletionQueue queue not None):
@@ -131,16 +127,14 @@
 
   cdef _c_shutdown(self, CompletionQueue queue, tag):
     self.is_shutting_down = True
-    operation_tag = OperationTag(tag, None)
-    operation_tag.shutting_down_server = self
-    cpython.Py_INCREF(operation_tag)
+    cdef _ServerShutdownTag server_shutdown_tag = _ServerShutdownTag(tag, self)
+    cpython.Py_INCREF(server_shutdown_tag)
     with nogil:
       grpc_server_shutdown_and_notify(
           self.c_server, queue.c_completion_queue,
-          <cpython.PyObject *>operation_tag)
+          <cpython.PyObject *>server_shutdown_tag)
 
   def shutdown(self, CompletionQueue queue not None, tag):
-    cdef OperationTag operation_tag
     if queue.is_shutting_down:
       raise ValueError("queue must be live")
     elif not self.is_started:
@@ -153,7 +147,8 @@
       self._c_shutdown(queue, tag)
 
   cdef notify_shutdown_complete(self):
-    # called only by a completion queue on receiving our shutdown operation tag
+    # called only after our server shutdown tag has emerged from a completion
+    # queue.
     self.is_shutdown = True
 
   def cancel_all_calls(self):
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/tag.pxd.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/tag.pxd.pxi
new file mode 100644
index 0000000..f9a3b5e
--- /dev/null
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/tag.pxd.pxi
@@ -0,0 +1,58 @@
+# 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 _Tag:
+
+  cdef object event(self, grpc_event c_event)
+
+
+cdef class _ConnectivityTag(_Tag):
+
+  cdef readonly object _user_tag
+
+  cdef ConnectivityEvent event(self, grpc_event c_event)
+
+
+cdef class _RequestCallTag(_Tag):
+
+  cdef readonly object _user_tag
+  cdef Call call
+  cdef CallDetails call_details
+  cdef grpc_metadata_array c_invocation_metadata
+
+  cdef void prepare(self)
+  cdef RequestCallEvent event(self, grpc_event c_event)
+
+
+cdef class _BatchOperationTag(_Tag):
+
+  cdef object _user_tag
+  cdef readonly object _operations
+  cdef readonly object _retained_call
+  cdef grpc_op *c_ops
+  cdef size_t c_nops
+
+  cdef void prepare(self)
+  cdef BatchOperationEvent event(self, grpc_event c_event)
+
+
+cdef class _ServerShutdownTag(_Tag):
+
+  cdef readonly object _user_tag
+  # This allows CompletionQueue to notify the Python Server object that the
+  # underlying GRPC core server has shutdown
+  cdef readonly Server _shutting_down_server
+
+  cdef ServerShutdownEvent event(self, grpc_event c_event)
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/tag.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/tag.pyx.pxi
new file mode 100644
index 0000000..aaca458
--- /dev/null
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/tag.pyx.pxi
@@ -0,0 +1,87 @@
+# 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 _Tag:
+
+  cdef object event(self, grpc_event c_event):
+    raise NotImplementedError()
+
+
+cdef class _ConnectivityTag(_Tag):
+
+  def __cinit__(self, user_tag):
+    self._user_tag = user_tag
+
+  cdef ConnectivityEvent event(self, grpc_event c_event):
+    return ConnectivityEvent(c_event.type, c_event.success, self._user_tag)
+
+
+cdef class _RequestCallTag(_Tag):
+
+  def __cinit__(self, user_tag):
+    self._user_tag = user_tag
+    self.call = None
+    self.call_details = None
+
+  cdef void prepare(self):
+    self.call = Call()
+    self.call_details = CallDetails()
+    grpc_metadata_array_init(&self.c_invocation_metadata)
+
+  cdef RequestCallEvent event(self, grpc_event c_event):
+    cdef tuple invocation_metadata = _metadata(&self.c_invocation_metadata)
+    grpc_metadata_array_destroy(&self.c_invocation_metadata)
+    return RequestCallEvent(
+        c_event.type, c_event.success, self._user_tag, self.call,
+        self.call_details, invocation_metadata)
+
+
+cdef class _BatchOperationTag:
+
+  def __cinit__(self, user_tag, operations, call):
+    self._user_tag = user_tag
+    self._operations = operations
+    self._retained_call = call
+
+  cdef void prepare(self):
+    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, operation in enumerate(self._operations):
+        (<Operation>operation).c()
+        self.c_ops[index] = (<Operation>operation).c_op
+
+  cdef BatchOperationEvent event(self, grpc_event c_event):
+    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 BatchOperationEvent(
+          c_event.type, c_event.success, self._user_tag, self._operations)
+    else:
+      return BatchOperationEvent(
+          c_event.type, c_event.success, self._user_tag, ())
+
+
+cdef class _ServerShutdownTag(_Tag):
+
+  def __cinit__(self, user_tag, shutting_down_server):
+    self._user_tag = user_tag
+    self._shutting_down_server = shutting_down_server
+
+  cdef ServerShutdownEvent event(self, grpc_event c_event):
+    self._shutting_down_server.notify_shutdown_complete()
+    return ServerShutdownEvent(c_event.type, c_event.success, self._user_tag)
\ No newline at end of file
diff --git a/src/python/grpcio/grpc/_cython/cygrpc.pxd b/src/python/grpcio/grpc/_cython/cygrpc.pxd
index 6fc5638..b32fa51 100644
--- a/src/python/grpcio/grpc/_cython/cygrpc.pxd
+++ b/src/python/grpcio/grpc/_cython/cygrpc.pxd
@@ -18,7 +18,10 @@
 include "_cygrpc/channel.pxd.pxi"
 include "_cygrpc/credentials.pxd.pxi"
 include "_cygrpc/completion_queue.pxd.pxi"
+include "_cygrpc/event.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"
+include "_cygrpc/tag.pxd.pxi"
diff --git a/src/python/grpcio/grpc/_cython/cygrpc.pyx b/src/python/grpcio/grpc/_cython/cygrpc.pyx
index d605229..5106394 100644
--- a/src/python/grpcio/grpc/_cython/cygrpc.pyx
+++ b/src/python/grpcio/grpc/_cython/cygrpc.pyx
@@ -25,10 +25,13 @@
 include "_cygrpc/channel.pyx.pxi"
 include "_cygrpc/credentials.pyx.pxi"
 include "_cygrpc/completion_queue.pyx.pxi"
+include "_cygrpc/event.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"
+include "_cygrpc/tag.pyx.pxi"
 
 #
 # initialize gRPC
diff --git a/src/python/grpcio/grpc/_server.py b/src/python/grpcio/grpc/_server.py
index 02d3af8..22244b9 100644
--- a/src/python/grpcio/grpc/_server.py
+++ b/src/python/grpcio/grpc/_server.py
@@ -50,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):
@@ -130,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
@@ -150,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
@@ -218,11 +217,10 @@
 
     def time_remaining(self):
         return max(
-            float(self._rpc_event.request_call_details.deadline) - time.time(),
-            0)
+            float(self._rpc_event.call_details.deadline) - time.time(), 0)
 
     def cancel(self):
-        self._rpc_event.operation_call.cancel()
+        self._rpc_event.call.cancel()
 
     def add_callback(self, callback):
         with self._state.condition:
@@ -237,23 +235,23 @@
             self._state.disable_next_compression = True
 
     def invocation_metadata(self):
-        return self._rpc_event.request_metadata
+        return self._rpc_event.invocation_metadata
 
     def peer(self):
-        return _common.decode(self._rpc_event.operation_call.peer())
+        return _common.decode(self._rpc_event.call.peer())
 
     def peer_identities(self):
-        return cygrpc.peer_identities(self._rpc_event.operation_call)
+        return cygrpc.peer_identities(self._rpc_event.call)
 
     def peer_identity_key(self):
-        id_key = cygrpc.peer_identity_key(self._rpc_event.operation_call)
+        id_key = cygrpc.peer_identity_key(self._rpc_event.call)
         return id_key if id_key is None else _common.decode(id_key)
 
     def auth_context(self):
         return {
             _common.decode(key): value
             for key, value in six.iteritems(
-                cygrpc.auth_context(self._rpc_event.operation_call))
+                cygrpc.auth_context(self._rpc_event.call))
         }
 
     def send_initial_metadata(self, initial_metadata):
@@ -262,9 +260,9 @@
                 _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(
+                    self._rpc_event.call.start_server_batch(
                         (operation,), _send_initial_metadata(self._state))
                     self._state.initial_metadata_allowed = False
                     self._state.due.add(_SEND_INITIAL_METADATA_TOKEN)
@@ -305,7 +303,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,9 +345,9 @@
             if state.client is _CANCELLED or state.statused:
                 return None
             else:
-                rpc_event.operation_call.start_server_batch(
-                    (cygrpc.operation_receive_message(_EMPTY_FLAGS),),
-                    _receive_message(state, rpc_event.operation_call,
+                rpc_event.call.start_server_batch(
+                    (cygrpc.ReceiveMessageOperation(_EMPTY_FLAGS),),
+                    _receive_message(state, rpc_event.call,
                                      request_deserializer))
                 state.due.add(_RECEIVE_MESSAGE_TOKEN)
                 while True:
@@ -357,8 +355,8 @@
                     if state.request is None:
                         if state.client is _CLOSED:
                             details = '"{}" requires exactly one request message.'.format(
-                                rpc_event.request_call_details.method)
-                            _abort(state, rpc_event.operation_call,
+                                rpc_event.call_details.method)
+                            _abort(state, rpc_event.call,
                                    cygrpc.StatusCode.unimplemented,
                                    _common.encode(details))
                             return None
@@ -379,13 +377,13 @@
     except Exception as exception:  # pylint: disable=broad-except
         with state.condition:
             if exception is state.abortion:
-                _abort(state, rpc_event.operation_call,
-                       cygrpc.StatusCode.unknown, b'RPC Aborted')
+                _abort(state, rpc_event.call, cygrpc.StatusCode.unknown,
+                       b'RPC Aborted')
             elif exception not in state.rpc_errors:
                 details = 'Exception calling application: {}'.format(exception)
                 logging.exception(details)
-                _abort(state, rpc_event.operation_call,
-                       cygrpc.StatusCode.unknown, _common.encode(details))
+                _abort(state, rpc_event.call, cygrpc.StatusCode.unknown,
+                       _common.encode(details))
         return None, False
 
 
@@ -397,13 +395,13 @@
     except Exception as exception:  # pylint: disable=broad-except
         with state.condition:
             if exception is state.abortion:
-                _abort(state, rpc_event.operation_call,
-                       cygrpc.StatusCode.unknown, b'RPC Aborted')
+                _abort(state, rpc_event.call, cygrpc.StatusCode.unknown,
+                       b'RPC Aborted')
             elif exception not in state.rpc_errors:
                 details = 'Exception iterating responses: {}'.format(exception)
                 logging.exception(details)
-                _abort(state, rpc_event.operation_call,
-                       cygrpc.StatusCode.unknown, _common.encode(details))
+                _abort(state, rpc_event.call, cygrpc.StatusCode.unknown,
+                       _common.encode(details))
         return None, False
 
 
@@ -411,7 +409,7 @@
     serialized_response = _common.serialize(response, response_serializer)
     if serialized_response is None:
         with state.condition:
-            _abort(state, rpc_event.operation_call, cygrpc.StatusCode.internal,
+            _abort(state, rpc_event.call, cygrpc.StatusCode.internal,
                    b'Failed to serialize response!')
         return None
     else:
@@ -424,17 +422,18 @@
             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))
+            rpc_event.call.start_server_batch(operations,
+                                              _send_message(state, token))
             state.due.add(token)
             while True:
                 state.condition.wait()
@@ -448,17 +447,17 @@
             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))
-            rpc_event.operation_call.start_server_batch(
+                    cygrpc.SendMessageOperation(serialized_response,
+                                                _EMPTY_FLAGS))
+            rpc_event.call.start_server_batch(
                 operations,
                 _send_status_from_server(state, _SEND_STATUS_FROM_SERVER_TOKEN))
             state.statused = True
@@ -525,7 +524,7 @@
 
 
 def _handle_stream_unary(rpc_event, state, method_handler, thread_pool):
-    request_iterator = _RequestIterator(state, rpc_event.operation_call,
+    request_iterator = _RequestIterator(state, rpc_event.call,
                                         method_handler.request_deserializer)
     return thread_pool.submit(
         _unary_response_in_pool, rpc_event, state, method_handler.stream_unary,
@@ -534,7 +533,7 @@
 
 
 def _handle_stream_stream(rpc_event, state, method_handler, thread_pool):
-    request_iterator = _RequestIterator(state, rpc_event.operation_call,
+    request_iterator = _RequestIterator(state, rpc_event.call,
                                         method_handler.request_deserializer)
     return thread_pool.submit(
         _stream_response_in_pool, rpc_event, state,
@@ -552,8 +551,8 @@
         return None
 
     handler_call_details = _HandlerCallDetails(
-        _common.decode(rpc_event.request_call_details.method),
-        rpc_event.request_metadata)
+        _common.decode(rpc_event.call_details.method),
+        rpc_event.invocation_metadata)
 
     if interceptor_pipeline is not None:
         return interceptor_pipeline.execute(query_handlers,
@@ -563,21 +562,21 @@
 
 
 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, (),))
+    rpc_event.call.start_server_batch(operations,
+                                      lambda ignored_event: (rpc_state, (),))
     return rpc_state
 
 
 def _handle_with_method_handler(rpc_event, method_handler, thread_pool):
     state = _RPCState()
     with state.condition:
-        rpc_event.operation_call.start_server_batch(
-            (cygrpc.operation_receive_close_on_server(_EMPTY_FLAGS),),
+        rpc_event.call.start_server_batch(
+            (cygrpc.ReceiveCloseOnServerOperation(_EMPTY_FLAGS),),
             _receive_close_on_server(state))
         state.due.add(_RECEIVE_CLOSE_ON_SERVER_TOKEN)
         if method_handler.request_streaming:
@@ -600,7 +599,7 @@
                  concurrency_exceeded):
     if not rpc_event.success:
         return None, None
-    if rpc_event.request_call_details.method is not None:
+    if rpc_event.call_details.method is not None:
         try:
             method_handler = _find_method_handler(rpc_event, generic_handlers,
                                                   interceptor_pipeline)
diff --git a/src/python/grpcio_tests/tests/tests.json b/src/python/grpcio_tests/tests/tests.json
index 3bf5308..e033c10 100644
--- a/src/python/grpcio_tests/tests/tests.json
+++ b/src/python/grpcio_tests/tests/tests.json
@@ -34,6 +34,7 @@
   "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",
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 7df8e2f..cdb3572 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
@@ -53,7 +53,7 @@
         self._state = state
         self._lock = threading.Lock()
         self._completion_queue = completion_queue
-        self._call = rpc_event.operation_call
+        self._call = rpc_event.call
 
     def __call__(self):
         with self._state.condition:
@@ -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,
@@ -170,13 +170,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..583136c 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,
@@ -71,8 +72,8 @@
 
         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(
+                server_request_call_event.call.start_server_batch([
+                    cygrpc.SendInitialMetadataOperation(
                         _common.INITIAL_METADATA, _common.EMPTY_FLAGS),
                 ], server_send_initial_metadata_tag))
             server_call_driver.add_due({
@@ -83,10 +84,9 @@
 
         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(
+                server_request_call_event.call.start_server_batch([
+                    cygrpc.ReceiveCloseOnServerOperation(_common.EMPTY_FLAGS),
+                    cygrpc.SendStatusFromServerOperation(
                         _common.TRAILING_METADATA, cygrpc.StatusCode.ok,
                         b'test details', _common.EMPTY_FLAGS),
                 ], server_complete_rpc_tag))
@@ -101,23 +101,24 @@
         client_complete_rpc_event = self.client_driver.event_with_tag(
             client_complete_rpc_tag)
 
-        return (_common.OperationResult(server_request_call_start_batch_result,
-                                        server_request_call_event.type,
-                                        server_request_call_event.success),
+        return (_common.OperationResult(
+            server_request_call_start_batch_result,
+            server_request_call_event.completion_type,
+            server_request_call_event.success), _common.OperationResult(
+                client_receive_initial_metadata_start_batch_result,
+                client_receive_initial_metadata_event.completion_type,
+                client_receive_initial_metadata_event.success),
                 _common.OperationResult(
-                    client_receive_initial_metadata_start_batch_result,
-                    client_receive_initial_metadata_event.type,
-                    client_receive_initial_metadata_event.success),
-                _common.OperationResult(client_complete_rpc_start_batch_result,
-                                        client_complete_rpc_event.type,
-                                        client_complete_rpc_event.success),
+                    client_complete_rpc_start_batch_result,
+                    client_complete_rpc_event.completion_type,
+                    client_complete_rpc_event.success), _common.OperationResult(
+                        server_send_initial_metadata_start_batch_result,
+                        server_send_initial_metadata_event.completion_type,
+                        server_send_initial_metadata_event.success),
                 _common.OperationResult(
-                    server_send_initial_metadata_start_batch_result,
-                    server_send_initial_metadata_event.type,
-                    server_send_initial_metadata_event.success),
-                _common.OperationResult(server_complete_rpc_start_batch_result,
-                                        server_complete_rpc_event.type,
-                                        server_complete_rpc_event.success),)
+                    server_complete_rpc_start_batch_result,
+                    server_complete_rpc_event.completion_type,
+                    server_complete_rpc_event.success),)
 
     def test_rpcs(self):
         expecteds = [(_common.SUCCESSFUL_OPERATION_RESULT,) *
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..c5cf606 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,
@@ -66,8 +63,8 @@
 
         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(
+                server_request_call_event.call.start_server_batch([
+                    cygrpc.SendInitialMetadataOperation(
                         _common.INITIAL_METADATA, _common.EMPTY_FLAGS),
                 ], server_send_initial_metadata_tag))
             self.server_driver.add_due({
@@ -78,12 +75,11 @@
 
         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(
+                server_request_call_event.call.start_server_batch([
+                    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,
@@ -96,23 +92,24 @@
         client_complete_rpc_event = self.client_driver.event_with_tag(
             client_complete_rpc_tag)
 
-        return (_common.OperationResult(server_request_call_start_batch_result,
-                                        server_request_call_event.type,
-                                        server_request_call_event.success),
+        return (_common.OperationResult(
+            server_request_call_start_batch_result,
+            server_request_call_event.completion_type,
+            server_request_call_event.success), _common.OperationResult(
+                client_receive_initial_metadata_start_batch_result,
+                client_receive_initial_metadata_event.completion_type,
+                client_receive_initial_metadata_event.success),
                 _common.OperationResult(
-                    client_receive_initial_metadata_start_batch_result,
-                    client_receive_initial_metadata_event.type,
-                    client_receive_initial_metadata_event.success),
-                _common.OperationResult(client_complete_rpc_start_batch_result,
-                                        client_complete_rpc_event.type,
-                                        client_complete_rpc_event.success),
+                    client_complete_rpc_start_batch_result,
+                    client_complete_rpc_event.completion_type,
+                    client_complete_rpc_event.success), _common.OperationResult(
+                        server_send_initial_metadata_start_batch_result,
+                        server_send_initial_metadata_event.completion_type,
+                        server_send_initial_metadata_event.success),
                 _common.OperationResult(
-                    server_send_initial_metadata_start_batch_result,
-                    server_send_initial_metadata_event.type,
-                    server_send_initial_metadata_event.success),
-                _common.OperationResult(server_complete_rpc_start_batch_result,
-                                        server_complete_rpc_event.type,
-                                        server_complete_rpc_event.success),)
+                    server_complete_rpc_start_batch_result,
+                    server_complete_rpc_event.completion_type,
+                    server_complete_rpc_event.success),)
 
     def test_rpcs(self):
         expecteds = [(_common.SUCCESSFUL_OPERATION_RESULT,) *
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 c7d1905..a5ec54e 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
@@ -159,15 +159,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,13 +175,13 @@
 
         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),
+                server_rpc_event.call.start_server_batch([
+                    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),
+                server_rpc_event.call.start_server_batch([
+                    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,13 +189,13 @@
             server_send_first_message_tag)
         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),
+                server_rpc_event.call.start_server_batch([
+                    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(
+                server_rpc_event.call.start_server_batch([
+                    cygrpc.ReceiveCloseOnServerOperation(_EMPTY_FLAGS),
+                    cygrpc.SendStatusFromServerOperation(
                         (), cygrpc.StatusCode.ok, b'test details',
                         _EMPTY_FLAGS),
                 ], server_complete_rpc_tag))
@@ -209,7 +209,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(
@@ -232,9 +232,8 @@
         self.assertEqual(cygrpc.CallError.ok, client_call_cancel_result)
         self.assertIs(server_rpc_tag, server_rpc_event.tag)
         self.assertEqual(cygrpc.CompletionType.operation_complete,
-                         server_rpc_event.type)
-        self.assertIsInstance(server_rpc_event.operation_call, cygrpc.Call)
-        self.assertEqual(0, len(server_rpc_event.batch_operations))
+                         server_rpc_event.completion_type)
+        self.assertIsInstance(server_rpc_event.call, cygrpc.Call)
 
 
 if __name__ == '__main__':
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 33a35ae..5453735 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)
@@ -92,7 +87,8 @@
         shutdown_tag = object()
         server.shutdown(completion_queue, shutdown_tag)
         event = completion_queue.poll()
-        self.assertEqual(cygrpc.CompletionType.operation_complete, event.type)
+        self.assertEqual(cygrpc.CompletionType.operation_complete,
+                         event.completion_type)
         self.assertIs(shutdown_tag, event.tag)
         del server
         del completion_queue
@@ -152,7 +148,7 @@
                 self.assertEqual(cygrpc.CallError.ok, call_result)
                 event = queue.poll(deadline)
                 self.assertEqual(cygrpc.CompletionType.operation_complete,
-                                 event.type)
+                                 event.completion_type)
                 self.assertTrue(event.success)
                 self.assertIs(tag, event.tag)
             except Exception as error:
@@ -174,7 +170,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'
@@ -196,13 +192,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(
@@ -210,33 +206,31 @@
 
         request_event = self.server_completion_queue.poll(cygrpc_deadline)
         self.assertEqual(cygrpc.CompletionType.operation_complete,
-                         request_event.type)
-        self.assertIsInstance(request_event.operation_call, cygrpc.Call)
+                         request_event.completion_type)
+        self.assertIsInstance(request_event.call, cygrpc.Call)
         self.assertIs(server_request_tag, request_event.tag)
-        self.assertEqual(0, len(request_event.batch_operations))
         self.assertTrue(
             test_common.metadata_transmitted(client_initial_metadata,
-                                             request_event.request_metadata))
-        self.assertEqual(METHOD, request_event.request_call_details.method)
-        self.assertEqual(self.expected_host,
-                         request_event.request_call_details.host)
+                                             request_event.invocation_metadata))
+        self.assertEqual(METHOD, request_event.call_details.method)
+        self.assertEqual(self.expected_host, request_event.call_details.host)
         self.assertLess(
-            abs(DEADLINE - float(request_event.request_call_details.deadline)),
+            abs(DEADLINE - float(request_event.call_details.deadline)),
             DEADLINE_TOLERANCE)
 
         server_call_tag = object()
-        server_call = request_event.operation_call
+        server_call = request_event.call
         server_initial_metadata = (
             (SERVER_INITIAL_METADATA_KEY, SERVER_INITIAL_METADATA_VALUE,),)
         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)
@@ -249,25 +243,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,
@@ -281,13 +274,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,
@@ -323,13 +316,12 @@
                                             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)
-        server_call = request_event.operation_call
+        server_call = request_event.call
 
         def perform_server_operations(operations, description):
             return self._perform_operations(operations, server_call,
@@ -337,8 +329,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
@@ -347,12 +338,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
@@ -360,13 +351,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")