mirror of https://github.com/grpc/grpc.git
Revert "Merge pull request #18727 from grpc/revert_compression"
This reverts commitpull/18732/head8054a731d1
, reversing changes made toc3d3cf8053
.
parent
8054a731d1
commit
f900eec41d
16 changed files with 893 additions and 195 deletions
@ -0,0 +1,55 @@ |
|||||||
|
# Copyright 2019 The 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. |
||||||
|
|
||||||
|
from grpc._cython import cygrpc |
||||||
|
|
||||||
|
NoCompression = cygrpc.CompressionAlgorithm.none |
||||||
|
Deflate = cygrpc.CompressionAlgorithm.deflate |
||||||
|
Gzip = cygrpc.CompressionAlgorithm.gzip |
||||||
|
|
||||||
|
_METADATA_STRING_MAPPING = { |
||||||
|
NoCompression: 'identity', |
||||||
|
Deflate: 'deflate', |
||||||
|
Gzip: 'gzip', |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
def _compression_algorithm_to_metadata_value(compression): |
||||||
|
return _METADATA_STRING_MAPPING[compression] |
||||||
|
|
||||||
|
|
||||||
|
def compression_algorithm_to_metadata(compression): |
||||||
|
return (cygrpc.GRPC_COMPRESSION_REQUEST_ALGORITHM_MD_KEY, |
||||||
|
_compression_algorithm_to_metadata_value(compression)) |
||||||
|
|
||||||
|
|
||||||
|
def create_channel_option(compression): |
||||||
|
return ((cygrpc.GRPC_COMPRESSION_CHANNEL_DEFAULT_ALGORITHM, |
||||||
|
int(compression)),) if compression else () |
||||||
|
|
||||||
|
|
||||||
|
def augment_metadata(metadata, compression): |
||||||
|
if not metadata and not compression: |
||||||
|
return None |
||||||
|
base_metadata = tuple(metadata) if metadata else () |
||||||
|
compression_metadata = ( |
||||||
|
compression_algorithm_to_metadata(compression),) if compression else () |
||||||
|
return base_metadata + compression_metadata |
||||||
|
|
||||||
|
|
||||||
|
__all__ = ( |
||||||
|
"NoCompression", |
||||||
|
"Deflate", |
||||||
|
"Gzip", |
||||||
|
) |
@ -0,0 +1,164 @@ |
|||||||
|
# Copyright 2019 the 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. |
||||||
|
""" Proxies a TCP connection between a single client-server pair. |
||||||
|
|
||||||
|
This proxy is not suitable for production, but should work well for cases in |
||||||
|
which a test needs to spy on the bytes put on the wire between a server and |
||||||
|
a client. |
||||||
|
""" |
||||||
|
|
||||||
|
from __future__ import absolute_import |
||||||
|
from __future__ import division |
||||||
|
from __future__ import print_function |
||||||
|
|
||||||
|
import datetime |
||||||
|
import select |
||||||
|
import socket |
||||||
|
import threading |
||||||
|
|
||||||
|
_TCP_PROXY_BUFFER_SIZE = 1024 |
||||||
|
_TCP_PROXY_TIMEOUT = datetime.timedelta(milliseconds=500) |
||||||
|
|
||||||
|
|
||||||
|
def _create_socket_ipv6(bind_address): |
||||||
|
listen_socket = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) |
||||||
|
listen_socket.bind((bind_address, 0, 0, 0)) |
||||||
|
return listen_socket |
||||||
|
|
||||||
|
|
||||||
|
def _create_socket_ipv4(bind_address): |
||||||
|
listen_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) |
||||||
|
listen_socket.bind((bind_address, 0)) |
||||||
|
return listen_socket |
||||||
|
|
||||||
|
|
||||||
|
def _init_listen_socket(bind_address): |
||||||
|
listen_socket = None |
||||||
|
if socket.has_ipv6: |
||||||
|
try: |
||||||
|
listen_socket = _create_socket_ipv6(bind_address) |
||||||
|
except socket.error: |
||||||
|
listen_socket = _create_socket_ipv4(bind_address) |
||||||
|
else: |
||||||
|
listen_socket = _create_socket_ipv4(bind_address) |
||||||
|
listen_socket.listen(1) |
||||||
|
return listen_socket, listen_socket.getsockname()[1] |
||||||
|
|
||||||
|
|
||||||
|
def _init_proxy_socket(gateway_address, gateway_port): |
||||||
|
proxy_socket = socket.create_connection((gateway_address, gateway_port)) |
||||||
|
return proxy_socket |
||||||
|
|
||||||
|
|
||||||
|
class TcpProxy(object): |
||||||
|
"""Proxies a TCP connection between one client and one server.""" |
||||||
|
|
||||||
|
def __init__(self, bind_address, gateway_address, gateway_port): |
||||||
|
self._bind_address = bind_address |
||||||
|
self._gateway_address = gateway_address |
||||||
|
self._gateway_port = gateway_port |
||||||
|
|
||||||
|
self._byte_count_lock = threading.RLock() |
||||||
|
self._sent_byte_count = 0 |
||||||
|
self._received_byte_count = 0 |
||||||
|
|
||||||
|
self._stop_event = threading.Event() |
||||||
|
|
||||||
|
self._port = None |
||||||
|
self._listen_socket = None |
||||||
|
self._proxy_socket = None |
||||||
|
|
||||||
|
# The following three attributes are owned by the serving thread. |
||||||
|
self._northbound_data = b"" |
||||||
|
self._southbound_data = b"" |
||||||
|
self._client_sockets = [] |
||||||
|
|
||||||
|
self._thread = threading.Thread(target=self._run_proxy) |
||||||
|
|
||||||
|
def start(self): |
||||||
|
self._listen_socket, self._port = _init_listen_socket( |
||||||
|
self._bind_address) |
||||||
|
self._proxy_socket = _init_proxy_socket(self._gateway_address, |
||||||
|
self._gateway_port) |
||||||
|
self._thread.start() |
||||||
|
|
||||||
|
def get_port(self): |
||||||
|
return self._port |
||||||
|
|
||||||
|
def _handle_reads(self, sockets_to_read): |
||||||
|
for socket_to_read in sockets_to_read: |
||||||
|
if socket_to_read is self._listen_socket: |
||||||
|
client_socket, client_address = socket_to_read.accept() |
||||||
|
self._client_sockets.append(client_socket) |
||||||
|
elif socket_to_read is self._proxy_socket: |
||||||
|
data = socket_to_read.recv(_TCP_PROXY_BUFFER_SIZE) |
||||||
|
with self._byte_count_lock: |
||||||
|
self._received_byte_count += len(data) |
||||||
|
self._northbound_data += data |
||||||
|
elif socket_to_read in self._client_sockets: |
||||||
|
data = socket_to_read.recv(_TCP_PROXY_BUFFER_SIZE) |
||||||
|
if data: |
||||||
|
with self._byte_count_lock: |
||||||
|
self._sent_byte_count += len(data) |
||||||
|
self._southbound_data += data |
||||||
|
else: |
||||||
|
self._client_sockets.remove(socket_to_read) |
||||||
|
else: |
||||||
|
raise RuntimeError('Unidentified socket appeared in read set.') |
||||||
|
|
||||||
|
def _handle_writes(self, sockets_to_write): |
||||||
|
for socket_to_write in sockets_to_write: |
||||||
|
if socket_to_write is self._proxy_socket: |
||||||
|
if self._southbound_data: |
||||||
|
self._proxy_socket.sendall(self._southbound_data) |
||||||
|
self._southbound_data = b"" |
||||||
|
elif socket_to_write in self._client_sockets: |
||||||
|
if self._northbound_data: |
||||||
|
socket_to_write.sendall(self._northbound_data) |
||||||
|
self._northbound_data = b"" |
||||||
|
|
||||||
|
def _run_proxy(self): |
||||||
|
while not self._stop_event.is_set(): |
||||||
|
expected_reads = (self._listen_socket, self._proxy_socket) + tuple( |
||||||
|
self._client_sockets) |
||||||
|
expected_writes = expected_reads |
||||||
|
sockets_to_read, sockets_to_write, _ = select.select( |
||||||
|
expected_reads, expected_writes, (), |
||||||
|
_TCP_PROXY_TIMEOUT.total_seconds()) |
||||||
|
self._handle_reads(sockets_to_read) |
||||||
|
self._handle_writes(sockets_to_write) |
||||||
|
for client_socket in self._client_sockets: |
||||||
|
client_socket.close() |
||||||
|
|
||||||
|
def stop(self): |
||||||
|
self._stop_event.set() |
||||||
|
self._thread.join() |
||||||
|
self._listen_socket.close() |
||||||
|
self._proxy_socket.close() |
||||||
|
|
||||||
|
def get_byte_count(self): |
||||||
|
with self._byte_count_lock: |
||||||
|
return self._sent_byte_count, self._received_byte_count |
||||||
|
|
||||||
|
def reset_byte_count(self): |
||||||
|
with self._byte_count_lock: |
||||||
|
self._byte_count = 0 |
||||||
|
self._received_byte_count = 0 |
||||||
|
|
||||||
|
def __enter__(self): |
||||||
|
self.start() |
||||||
|
return self |
||||||
|
|
||||||
|
def __exit__(self, exc_type, exc_val, exc_tb): |
||||||
|
self.stop() |
Loading…
Reference in new issue