diff --git a/.github/workflows/RavenClient.yml b/.github/workflows/RavenClient.yml index 38ef72c4..8dc54813 100644 --- a/.github/workflows/RavenClient.yml +++ b/.github/workflows/RavenClient.yml @@ -75,6 +75,9 @@ jobs: - name: Install embedded RavenDB run: pip install ravendb-embedded + - name: Install zstandard + run: pip install zstandard + - name: Run certifi script run: python ./.github/workflows/add_ca.py diff --git a/ravendb/documents/commands/stream.py b/ravendb/documents/commands/stream.py index 48c7123d..cc0ee03b 100644 --- a/ravendb/documents/commands/stream.py +++ b/ravendb/documents/commands/stream.py @@ -9,7 +9,7 @@ from ravendb.http.server_node import ServerNode from ravendb.http.raven_command import RavenCommand, RavenCommandResponseType from ravendb.json.metadata_as_dictionary import MetadataAsDictionary - +from ravendb.util.request_utils import RequestUtils _T = TypeVar("_T") @@ -52,15 +52,9 @@ def process_response(self, cache: HttpCache, response: requests.Response, url) - raise RuntimeError("Unable to process stream response", e) def send(self, session: requests.Session, request: requests.Request) -> requests.Response: - return session.request( - request.method, - url=request.url, - data=request.data, - files=request.files, - cert=session.cert, - headers=request.headers, - stream=True, - ) + prepared_request = session.prepare_request(request) + RequestUtils.remove_zstd_encoding(prepared_request) + return session.send(prepared_request, cert=session.cert, stream=True) def is_read_request(self) -> bool: return True @@ -97,15 +91,9 @@ def process_response(self, cache: HttpCache, response: requests.Response, url) - raise RuntimeError("Unable to process stream response: " + e.args[0], e) def send(self, session: requests.Session, request: requests.Request) -> requests.Response: - return session.request( - request.method, - url=request.url, - data=request.data, - files=request.files, - cert=session.cert, - headers=request.headers, - stream=True, - ) + prepared_request = session.prepare_request(request) + RequestUtils.remove_zstd_encoding(prepared_request) + return session.send(prepared_request, cert=session.cert, stream=True) def is_read_request(self) -> bool: return True diff --git a/ravendb/http/raven_command.py b/ravendb/http/raven_command.py index baa9f3a2..373afbe9 100644 --- a/ravendb/http/raven_command.py +++ b/ravendb/http/raven_command.py @@ -12,6 +12,7 @@ from ravendb.http.http_cache import HttpCache from ravendb.http.misc import ResponseDisposeHandling from ravendb.http.server_node import ServerNode +from ravendb.util.request_utils import RequestUtils class RavenCommandResponseType(Enum): @@ -97,14 +98,9 @@ def set_response(self, response: Optional[str], from_cache: bool) -> None: ) def send(self, session: requests.Session, request: requests.Request) -> requests.Response: - return session.request( - request.method, - url=request.url, - data=request.data, - files=request.files, - cert=session.cert, - headers=request.headers, - ) + prepared_request = session.prepare_request(request) + RequestUtils.remove_zstd_encoding(prepared_request) + return session.send(prepared_request, cert=session.cert) def set_response_raw(self, response: requests.Response, stream: bytes) -> None: raise RuntimeError( diff --git a/ravendb/tests/issue_tests/test_RDBC-940.py b/ravendb/tests/issue_tests/test_RDBC-940.py new file mode 100644 index 00000000..cd528874 --- /dev/null +++ b/ravendb/tests/issue_tests/test_RDBC-940.py @@ -0,0 +1,28 @@ +from ravendb.tests.test_base import TestBase + + +class TestDocument: + def __init__(self, name: str = None): + self.name = name + + +class TestRDBC940(TestBase): + def setUp(self): + super(TestRDBC940, self).setUp() + + def test_operations_with_zstandard_imported(self): + import zstandard + + document_id = "test-documents/1" + + with self.store.open_session() as session: + test_doc = TestDocument(name="Test Document") + session.store(test_doc, document_id) + session.save_changes() + + with self.store.open_session() as session: + loaded_doc = session.load(document_id, TestDocument) + + with self.store.open_session() as session: + session.delete(document_id) + session.save_changes() diff --git a/ravendb/util/request_utils.py b/ravendb/util/request_utils.py new file mode 100644 index 00000000..aeebffbb --- /dev/null +++ b/ravendb/util/request_utils.py @@ -0,0 +1,20 @@ +import requests + + +class RequestUtils: + + # https://issues.hibernatingrhinos.com/issue/RDBC-940 + # If user has installed module 'zstd' or 'zstandard', + # 'requests' module will automatically add 'zstd' to 'Accept-Encoding' header. + # This causes exceptions. Excluding 'zstd' from the header in this workaround, + # while we keep investigating cause of the issue. + @staticmethod + def remove_zstd_encoding(request: requests.PreparedRequest) -> None: + accept_encoding = request.headers.get("Accept-Encoding") + + if "zstd" in accept_encoding: + encodings = [ + encoding.strip() for encoding in accept_encoding.split(",") if encoding.strip().lower() != "zstd" + ] + new_header_value = ", ".join(encodings) + request.headers["Accept-Encoding"] = new_header_value diff --git a/setup.py b/setup.py index 58040024..4e208501 100644 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ setup( name="ravendb", packages=find_packages(exclude=["*.tests.*", "tests", "*.tests", "tests.*"]), - version="7.0.2", + version="7.0.2.post1", long_description_content_type="text/markdown", long_description=open("README_pypi.md").read(), description="Python client for RavenDB NoSQL Database",