diff --git a/ipfshttpclient/client/__init__.py b/ipfshttpclient/client/__init__.py index d5a57b9e..3410c261 100644 --- a/ipfshttpclient/client/__init__.py +++ b/ipfshttpclient/client/__init__.py @@ -98,7 +98,15 @@ def connect(addr=DEFAULT_ADDR, base=DEFAULT_BASE, client = Client(addr, base, chunk_size, session, **defaults) # Query version number from daemon and validate it - assert_version(client.version()['Version']) + version_str = client.version()["Version"] + assert_version(version_str) + + # Apply workarounds based on daemon version + version = tuple(map(int, version_str.split('-', 1)[0].split('.'))) + if version < (0, 4, 19): # pragma: no cover (workaround) + #WORKAROUND: Go-IPFS randomly fucks up streaming requests if they are not + # `Connection: close` (https://github.com/ipfs/go-ipfs/issues/5168) + client._workarounds.add("close_conn_on_upload") return client diff --git a/ipfshttpclient/client/base.py b/ipfshttpclient/client/base.py index d3ea5c2c..0c4e2985 100644 --- a/ipfshttpclient/client/base.py +++ b/ipfshttpclient/client/base.py @@ -119,4 +119,6 @@ def __init__(self, addr=DEFAULT_ADDR, base=DEFAULT_BASE, self._client = self._clientfactory(addr, base, **defaults) if session: - self._client.open_session() \ No newline at end of file + self._client.open_session() + + self._workarounds = self._client.workarounds diff --git a/ipfshttpclient/http.py b/ipfshttpclient/http.py index 10717652..356877cd 100644 --- a/ipfshttpclient/http.py +++ b/ipfshttpclient/http.py @@ -150,6 +150,8 @@ class HTTPClient(object): The address where the IPFS daemon may be reached base : str The path prefix for API calls + workarounds : Set[str] + List of daemon workarounds to apply timeout : Union[numbers.Real, Tuple[numbers.Real, numbers.Real], NoneType] The default number of seconds to wait when establishing a connection to the daemon and waiting for returned data before throwing @@ -164,7 +166,7 @@ class HTTPClient(object): __metaclass__ = abc.ABCMeta - def __init__(self, addr, base, **defaults): + def __init__(self, addr, base, workarounds=None, **defaults): addr = multiaddr.Multiaddr(addr) addr_iter = iter(addr.items()) @@ -222,6 +224,8 @@ def __init__(self, addr, base, **defaults): self.defaults = defaults self._session = None + + self.workarounds = workarounds if workarounds else set() def open_session(self): """Open a persistent backend session that allows reusing HTTP @@ -282,6 +286,11 @@ def _do_raise_for_status(self, response): def _request(self, method, url, params, parser, stream=False, files=None, headers={}, data=None, timeout=120): + if "close_conn_on_upload" in self.workarounds \ + and method.upper() not in ("GET", "HEAD"): # pragma: no cover (workaround) + headers = headers.copy() + headers["Connection"] = "close" + # Do HTTP request (synchronously) res = self._do_request(method, url, params=params, stream=stream, files=files, headers=headers, data=data, diff --git a/ipfshttpclient/multipart.py b/ipfshttpclient/multipart.py index a996d968..de4a19c1 100644 --- a/ipfshttpclient/multipart.py +++ b/ipfshttpclient/multipart.py @@ -138,10 +138,6 @@ def __init__(self, name, chunk_size=default_chunk_size): self._headers = content_disposition_headers(name, disptype='form-data') self._headers.update(multipart_content_type_headers(self._boundary, subtype='form-data')) - #WORKAROUND: Go-IPFS randomly fucks up streaming requests if they are not - # `Connection: close` (https://github.com/ipfs/go-ipfs/issues/5168) - self._headers["Connection"] = "close" - super(StreamBase, self).__init__() def headers(self): diff --git a/test/unit/test_multipart.py b/test/unit/test_multipart.py index a5ebd9e2..3081f790 100644 --- a/test/unit/test_multipart.py +++ b/test/unit/test_multipart.py @@ -142,8 +142,7 @@ def test__gen_headers(self): name = "test_name" generator = StreamBaseSub(name) - expected = b'Connection: close\r\n' \ - + b'Content-Disposition: form-data; filename="test_name"\r\n' \ + expected = b'Content-Disposition: form-data; filename="test_name"\r\n' \ + b'Content-Type: multipart/form-data; ' \ + b'boundary="' + generator._boundary.encode() + b'"\r\n\r\n'