diff options
author | Joffrey F <joffrey@docker.com> | 2017-11-01 18:03:29 -0700 |
---|---|---|
committer | Joffrey F <f.joffrey@gmail.com> | 2017-11-07 15:18:26 -0800 |
commit | e055729104dbc60bb9bbebce09686ac8a94c5809 (patch) | |
tree | 878a186602c464e981b97fd647aefe86799f4cb6 | |
parent | 047c67b31e2087d5e900072166921d55649f8b6f (diff) | |
download | docker-py-e055729104dbc60bb9bbebce09686ac8a94c5809.tar.gz |
Disable buffering based on presence of Connection Upgrade headers
Signed-off-by: Joffrey F <joffrey@docker.com>
-rw-r--r-- | Makefile | 20 | ||||
-rw-r--r-- | docker/transport/unixconn.py | 52 |
2 files changed, 35 insertions, 37 deletions
@@ -27,19 +27,19 @@ test: flake8 unit-test unit-test-py3 integration-dind integration-dind-ssl .PHONY: unit-test unit-test: build - docker run --rm docker-sdk-python py.test tests/unit + docker run -t --rm docker-sdk-python py.test tests/unit .PHONY: unit-test-py3 unit-test-py3: build-py3 - docker run --rm docker-sdk-python3 py.test tests/unit + docker run -t --rm docker-sdk-python3 py.test tests/unit .PHONY: integration-test integration-test: build - docker run --rm -v /var/run/docker.sock:/var/run/docker.sock docker-sdk-python py.test tests/integration/${file} + docker run -t --rm -v /var/run/docker.sock:/var/run/docker.sock docker-sdk-python py.test -v tests/integration/${file} .PHONY: integration-test-py3 integration-test-py3: build-py3 - docker run --rm -v /var/run/docker.sock:/var/run/docker.sock docker-sdk-python3 py.test tests/integration/${file} + docker run -t --rm -v /var/run/docker.sock:/var/run/docker.sock docker-sdk-python3 py.test tests/integration/${file} TEST_API_VERSION ?= 1.30 TEST_ENGINE_VERSION ?= 17.06.0-ce @@ -49,9 +49,9 @@ integration-dind: build build-py3 docker rm -vf dpy-dind || : docker run -d --name dpy-dind --privileged dockerswarm/dind:${TEST_ENGINE_VERSION} dockerd\ -H tcp://0.0.0.0:2375 --experimental - docker run --rm --env="DOCKER_HOST=tcp://docker:2375" --env="DOCKER_TEST_API_VERSION=${TEST_API_VERSION}"\ + docker run -t --rm --env="DOCKER_HOST=tcp://docker:2375" --env="DOCKER_TEST_API_VERSION=${TEST_API_VERSION}"\ --link=dpy-dind:docker docker-sdk-python py.test tests/integration - docker run --rm --env="DOCKER_HOST=tcp://docker:2375" --env="DOCKER_TEST_API_VERSION=${TEST_API_VERSION}"\ + docker run -t --rm --env="DOCKER_HOST=tcp://docker:2375" --env="DOCKER_TEST_API_VERSION=${TEST_API_VERSION}"\ --link=dpy-dind:docker docker-sdk-python3 py.test tests/integration docker rm -vf dpy-dind @@ -63,21 +63,21 @@ integration-dind-ssl: build-dind-certs build build-py3 -v /tmp --privileged dockerswarm/dind:${TEST_ENGINE_VERSION} dockerd --tlsverify\ --tlscacert=/certs/ca.pem --tlscert=/certs/server-cert.pem\ --tlskey=/certs/server-key.pem -H tcp://0.0.0.0:2375 --experimental - docker run --rm --volumes-from dpy-dind-ssl --env="DOCKER_HOST=tcp://docker:2375"\ + docker run -t --rm --volumes-from dpy-dind-ssl --env="DOCKER_HOST=tcp://docker:2375"\ --env="DOCKER_TLS_VERIFY=1" --env="DOCKER_CERT_PATH=/certs" --env="DOCKER_TEST_API_VERSION=${TEST_API_VERSION}"\ --link=dpy-dind-ssl:docker docker-sdk-python py.test tests/integration - docker run --rm --volumes-from dpy-dind-ssl --env="DOCKER_HOST=tcp://docker:2375"\ + docker run -t --rm --volumes-from dpy-dind-ssl --env="DOCKER_HOST=tcp://docker:2375"\ --env="DOCKER_TLS_VERIFY=1" --env="DOCKER_CERT_PATH=/certs" --env="DOCKER_TEST_API_VERSION=${TEST_API_VERSION}"\ --link=dpy-dind-ssl:docker docker-sdk-python3 py.test tests/integration docker rm -vf dpy-dind-ssl dpy-dind-certs .PHONY: flake8 flake8: build - docker run --rm docker-sdk-python flake8 docker tests + docker run -t --rm docker-sdk-python flake8 docker tests .PHONY: docs docs: build-docs - docker run --rm -it -v `pwd`:/src docker-sdk-python-docs sphinx-build docs docs/_build + docker run --rm -t -v `pwd`:/src docker-sdk-python-docs sphinx-build docs docs/_build .PHONY: shell shell: build diff --git a/docker/transport/unixconn.py b/docker/transport/unixconn.py index 16e22a8..7cb8771 100644 --- a/docker/transport/unixconn.py +++ b/docker/transport/unixconn.py @@ -18,7 +18,20 @@ except ImportError: RecentlyUsedContainer = urllib3._collections.RecentlyUsedContainer +class UnixHTTPResponse(httplib.HTTPResponse, object): + def __init__(self, sock, *args, **kwargs): + disable_buffering = kwargs.pop('disable_buffering', False) + super(UnixHTTPResponse, self).__init__(sock, *args, **kwargs) + if disable_buffering is True: + # We must first create a new pointer then close the old one + # to avoid closing the underlying socket. + new_fp = sock.makefile('rb', 0) + self.fp.close() + self.fp = new_fp + + class UnixHTTPConnection(httplib.HTTPConnection, object): + def __init__(self, base_url, unix_socket, timeout=60): super(UnixHTTPConnection, self).__init__( 'localhost', timeout=timeout @@ -26,6 +39,7 @@ class UnixHTTPConnection(httplib.HTTPConnection, object): self.base_url = base_url self.unix_socket = unix_socket self.timeout = timeout + self.disable_buffering = False def connect(self): sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) @@ -33,24 +47,16 @@ class UnixHTTPConnection(httplib.HTTPConnection, object): sock.connect(self.unix_socket) self.sock = sock + def putheader(self, header, *values): + super(UnixHTTPConnection, self).putheader(header, *values) + if header == 'Connection' and 'Upgrade' in values: + self.disable_buffering = True -class AttachHTTPResponse(httplib.HTTPResponse): - ''' - A HTTPResponse object that doesn't use a buffered fileobject. - ''' - def __init__(self, sock, *args, **kwargs): - # Delegate to super class - httplib.HTTPResponse.__init__(self, sock, *args, **kwargs) - - # Override fp with a fileobject that doesn't buffer - self.fp = sock.makefile('rb', 0) - + def response_class(self, sock, *args, **kwargs): + if self.disable_buffering: + kwargs['disable_buffering'] = True -class AttachUnixHTTPConnection(UnixHTTPConnection): - ''' - A HTTPConnection that returns responses that don't used buffering. - ''' - response_class = AttachHTTPResponse + return UnixHTTPResponse(sock, *args, **kwargs) class UnixHTTPConnectionPool(urllib3.connectionpool.HTTPConnectionPool): @@ -63,17 +69,9 @@ class UnixHTTPConnectionPool(urllib3.connectionpool.HTTPConnectionPool): self.timeout = timeout def _new_conn(self): - # Special case for attach url, as we do a http upgrade to tcp and - # a buffered connection can cause data loss. - path = urllib3.util.parse_url(self.base_url).path - if path.endswith('attach'): - return AttachUnixHTTPConnection( - self.base_url, self.socket_path, self.timeout - ) - else: - return UnixHTTPConnection( - self.base_url, self.socket_path, self.timeout - ) + return UnixHTTPConnection( + self.base_url, self.socket_path, self.timeout + ) class UnixAdapter(requests.adapters.HTTPAdapter): |