Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-geventhttpclient for 
openSUSE:Factory checked in at 2026-03-23 17:15:11
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-geventhttpclient (Old)
 and      /work/SRC/openSUSE:Factory/.python-geventhttpclient.new.8177 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-geventhttpclient"

Mon Mar 23 17:15:11 2026 rev:15 rq:1342004 version:2.3.9

Changes:
--------
--- 
/work/SRC/openSUSE:Factory/python-geventhttpclient/python-geventhttpclient.changes
  2026-01-08 15:29:23.269953838 +0100
+++ 
/work/SRC/openSUSE:Factory/.python-geventhttpclient.new.8177/python-geventhttpclient.changes
        2026-03-23 17:17:21.163617385 +0100
@@ -1,0 +2,10 @@
+Mon Mar 23 08:24:32 UTC 2026 - John Paul Adrian Glaubitz 
<[email protected]>
+
+- Update to 2.3.9
+  * Use select() for socket validation with stdlib SSL support
+    by @devamsheth21 in (#240)
+- from version 2.3.8
+  * feat: Add connection validation to prevent stale connection
+    reuse by @devamsheth21 in (#238)
+
+-------------------------------------------------------------------

Old:
----
  geventhttpclient-2.3.7.tar.gz
  python-geventhttpclient-2.3.7.tar.gz

New:
----
  geventhttpclient-2.3.9.tar.gz
  python-geventhttpclient-2.3.9.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-geventhttpclient.spec ++++++
--- /var/tmp/diff_new_pack.WumvCn/_old  2026-03-23 17:17:21.719640509 +0100
+++ /var/tmp/diff_new_pack.WumvCn/_new  2026-03-23 17:17:21.719640509 +0100
@@ -18,7 +18,7 @@
 
 %{?sle15_python_module_pythons}
 Name:           python-geventhttpclient
-Version:        2.3.7
+Version:        2.3.9
 Release:        0
 Summary:        HTTP client library for gevent
 License:        MIT

++++++ geventhttpclient-2.3.7.tar.gz -> geventhttpclient-2.3.9.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/geventhttpclient-2.3.7/PKG-INFO 
new/geventhttpclient-2.3.9/PKG-INFO
--- old/geventhttpclient-2.3.7/PKG-INFO 2025-12-07 20:15:19.205313700 +0100
+++ new/geventhttpclient-2.3.9/PKG-INFO 2026-03-03 08:35:11.159793900 +0100
@@ -1,6 +1,6 @@
 Metadata-Version: 2.4
 Name: geventhttpclient
-Version: 2.3.7
+Version: 2.3.9
 Summary: HTTP client library for gevent
 Author-email: Antonin Amand <[email protected]>
 License-Expression: MIT
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/geventhttpclient-2.3.7/pyproject.toml 
new/geventhttpclient-2.3.9/pyproject.toml
--- old/geventhttpclient-2.3.7/pyproject.toml   2025-12-07 20:15:13.000000000 
+0100
+++ new/geventhttpclient-2.3.9/pyproject.toml   2026-03-03 08:35:03.000000000 
+0100
@@ -5,7 +5,7 @@
 
 [project]
 name = "geventhttpclient"
-version = "2.3.7" # don't forget to update version __init__.py as well
+version = "2.3.9" # don't forget to update version __init__.py as well
 description = "HTTP client library for gevent"
 readme = "README.md"
 requires-python = ">=3.9"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/geventhttpclient-2.3.7/src/geventhttpclient/__init__.py 
new/geventhttpclient-2.3.9/src/geventhttpclient/__init__.py
--- old/geventhttpclient-2.3.7/src/geventhttpclient/__init__.py 2025-12-07 
20:15:13.000000000 +0100
+++ new/geventhttpclient-2.3.9/src/geventhttpclient/__init__.py 2026-03-03 
08:35:03.000000000 +0100
@@ -1,6 +1,6 @@
 # package
 
-__version__ = "2.3.7"  # don't forget to update version in pyproject.toml as 
well
+__version__ = "2.3.9"  # don't forget to update version in pyproject.toml as 
well
 
 from geventhttpclient.api import delete, get, head, options, patch, post, put, 
request
 from geventhttpclient.client import HTTPClient
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/geventhttpclient-2.3.7/src/geventhttpclient/connectionpool.py 
new/geventhttpclient-2.3.9/src/geventhttpclient/connectionpool.py
--- old/geventhttpclient-2.3.7/src/geventhttpclient/connectionpool.py   
2025-12-07 20:15:13.000000000 +0100
+++ new/geventhttpclient-2.3.9/src/geventhttpclient/connectionpool.py   
2026-03-03 08:35:03.000000000 +0100
@@ -1,4 +1,6 @@
 import os
+import socket
+import select
 
 import gevent.queue
 import gevent.socket
@@ -125,7 +127,7 @@
         if first_error:
             raise first_error
         else:
-            raise RuntimeError(f"Cannot resolve {self._host}:{self._port}")
+            raise RuntimeError(f"Cannot resolve 
{self._connection_host}:{self._connection_port}")
 
     def after_connect(self, sock):
         pass
@@ -149,19 +151,57 @@
             if not parts or parts[1] != b"200":
                 raise RuntimeError(f"Error response from Proxy server : 
{resp}")
 
+    def _is_socket_alive(self, sock):
+        """Check if a socket is still connected and alive.
+
+        Uses select() to check if socket is readable. An idle keep-alive socket
+        should NOT be readable.
+
+        Returns False if connection is closed or broken.
+        """
+        if sock is None:
+            return False
+        try:
+            # Proactive check: A closed socket has a fileno of -1.
+            if sock.fileno() < 0:
+                return False
+            # If the socket is readable while idle, it's either a FIN or dirty.
+            ready_to_read, _, _ = select.select([sock], [], [], 0.0)
+            if ready_to_read:
+                return False
+            
+            return True
+        except (OSError, ValueError, socket.error):
+            return False
+
     def get_socket(self):
         """get a socket from the pool. This blocks until one is available."""
         self._semaphore.acquire()
         if self._closed:
             raise RuntimeError("connection pool closed")
-        try:
-            return self._socket_queue.get(block=False)
-        except gevent.queue.Empty:
+
+        # Try to get a valid connection from the pool
+        while not self._socket_queue.empty():
             try:
-                return self._create_socket()
-            except:  # noqa
-                self._semaphore.release()
-                raise
+                sock = self._socket_queue.get(block=False)
+                if self._is_socket_alive(sock):
+                    # Connection is still alive, return it
+                    return sock
+                else:
+                    # Connection is dead, close it and try next
+                    try:
+                        sock.close()
+                    except:  # noqa
+                        pass
+            except gevent.queue.Empty:
+                break
+
+        # No valid connections in pool, create a new one
+        try:
+            return self._create_socket()
+        except:  # noqa
+            self._semaphore.release()
+            raise
 
     def return_socket(self, sock):
         """return a socket to the pool."""
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/geventhttpclient-2.3.7/src/geventhttpclient.egg-info/PKG-INFO 
new/geventhttpclient-2.3.9/src/geventhttpclient.egg-info/PKG-INFO
--- old/geventhttpclient-2.3.7/src/geventhttpclient.egg-info/PKG-INFO   
2025-12-07 20:15:19.000000000 +0100
+++ new/geventhttpclient-2.3.9/src/geventhttpclient.egg-info/PKG-INFO   
2026-03-03 08:35:11.000000000 +0100
@@ -1,6 +1,6 @@
 Metadata-Version: 2.4
 Name: geventhttpclient
-Version: 2.3.7
+Version: 2.3.9
 Summary: HTTP client library for gevent
 Author-email: Antonin Amand <[email protected]>
 License-Expression: MIT
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/geventhttpclient-2.3.7/tests/test_client.py 
new/geventhttpclient-2.3.9/tests/test_client.py
--- old/geventhttpclient-2.3.7/tests/test_client.py     2025-12-07 
20:15:13.000000000 +0100
+++ new/geventhttpclient-2.3.9/tests/test_client.py     2026-03-03 
08:35:03.000000000 +0100
@@ -1,4 +1,5 @@
 import json
+import socket
 
 import gevent.pool
 import gevent.queue
@@ -7,6 +8,7 @@
 
 from geventhttpclient import __version__
 from geventhttpclient.client import METHOD_GET, HTTPClient
+from geventhttpclient.connectionpool import ConnectionPool
 from tests.common import HTTPBIN_HOST, LISTENER, check_upload, server, 
wsgiserver
 
 
@@ -350,3 +352,32 @@
     assert count == 5
     # ensure at least 3 of requests got 200
     assert ok_count >= 3
+
+
+class TestIsSocketAlive:
+    """Unit tests for ConnectionPool._is_socket_alive()"""
+
+    def test_closed_socket_returns_false(self):
+        sock = socket.socket()
+        sock.close()
+        pool = ConnectionPool("127.0.0.1", 80, "127.0.0.1", 80)
+        assert sock.fileno() < 0
+        assert pool._is_socket_alive(sock) is False
+
+    def test_healthy_socket_returns_true(self):
+        s1, s2 = socket.socketpair()
+        try:
+            pool = ConnectionPool("127.0.0.1", 80, "127.0.0.1", 80)
+            assert pool._is_socket_alive(s1) is True
+        finally:
+            s1.close()
+            s2.close()
+
+    def test_peer_orderly_close_returns_false(self):
+        s1, s2 = socket.socketpair()
+        try:
+            s2.close()
+            pool = ConnectionPool("127.0.0.1", 80, "127.0.0.1", 80)
+            assert pool._is_socket_alive(s1) is False
+        finally:
+            s1.close()

++++++ python-geventhttpclient-2.3.7.tar.gz -> 
python-geventhttpclient-2.3.9.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/geventhttpclient-2.3.7/.github/workflows/publish.yml 
new/geventhttpclient-2.3.9/.github/workflows/publish.yml
--- old/geventhttpclient-2.3.7/.github/workflows/publish.yml    2025-12-07 
19:55:26.000000000 +0100
+++ new/geventhttpclient-2.3.9/.github/workflows/publish.yml    2026-03-03 
08:31:41.000000000 +0100
@@ -24,7 +24,9 @@
       - uses: docker/setup-qemu-action@v3
         if: ${{ matrix.os == 'ubuntu-latest' }}
         name: Set up QEMU
-      - run: pipx run cibuildwheel==3.3.0 --output-dir wheelhouse
+      - name: Install pipx
+        run: python -m pip install -U pipx
+      - run: pipx run cibuildwheel --output-dir wheelhouse
         name: Run build wheel
         env:
           CIBW_ARCHS_MACOS: "x86_64 universal2 arm64"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/geventhttpclient-2.3.7/pyproject.toml 
new/geventhttpclient-2.3.9/pyproject.toml
--- old/geventhttpclient-2.3.7/pyproject.toml   2025-12-07 19:55:26.000000000 
+0100
+++ new/geventhttpclient-2.3.9/pyproject.toml   2026-03-03 08:31:41.000000000 
+0100
@@ -5,7 +5,7 @@
 
 [project]
 name = "geventhttpclient"
-version = "2.3.7" # don't forget to update version __init__.py as well
+version = "2.3.9" # don't forget to update version __init__.py as well
 description = "HTTP client library for gevent"
 readme = "README.md"
 requires-python = ">=3.9"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/geventhttpclient-2.3.7/release.md 
new/geventhttpclient-2.3.9/release.md
--- old/geventhttpclient-2.3.7/release.md       2025-12-07 19:55:26.000000000 
+0100
+++ new/geventhttpclient-2.3.9/release.md       2026-03-03 08:31:41.000000000 
+0100
@@ -1,6 +1,6 @@
 # Making new releases
 
-- Bump version in src/geventhttpclient/\__init__.py
-- Bump version in setup.py
+- Bump version in `src/geventhttpclient/__init__.py`
+- Bump version in `pyproject.toml`
 - Make a GitHub release (which also makes a git tag)
 - Trigger the publish action 
https://github.com/geventhttpclient/geventhttpclient/actions/workflows/publish.yml
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/geventhttpclient-2.3.7/src/geventhttpclient/__init__.py 
new/geventhttpclient-2.3.9/src/geventhttpclient/__init__.py
--- old/geventhttpclient-2.3.7/src/geventhttpclient/__init__.py 2025-12-07 
19:55:26.000000000 +0100
+++ new/geventhttpclient-2.3.9/src/geventhttpclient/__init__.py 2026-03-03 
08:31:41.000000000 +0100
@@ -1,6 +1,6 @@
 # package
 
-__version__ = "2.3.7"  # don't forget to update version in pyproject.toml as 
well
+__version__ = "2.3.9"  # don't forget to update version in pyproject.toml as 
well
 
 from geventhttpclient.api import delete, get, head, options, patch, post, put, 
request
 from geventhttpclient.client import HTTPClient
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/geventhttpclient-2.3.7/src/geventhttpclient/connectionpool.py 
new/geventhttpclient-2.3.9/src/geventhttpclient/connectionpool.py
--- old/geventhttpclient-2.3.7/src/geventhttpclient/connectionpool.py   
2025-12-07 19:55:26.000000000 +0100
+++ new/geventhttpclient-2.3.9/src/geventhttpclient/connectionpool.py   
2026-03-03 08:31:41.000000000 +0100
@@ -1,4 +1,6 @@
 import os
+import socket
+import select
 
 import gevent.queue
 import gevent.socket
@@ -125,7 +127,7 @@
         if first_error:
             raise first_error
         else:
-            raise RuntimeError(f"Cannot resolve {self._host}:{self._port}")
+            raise RuntimeError(f"Cannot resolve 
{self._connection_host}:{self._connection_port}")
 
     def after_connect(self, sock):
         pass
@@ -149,19 +151,57 @@
             if not parts or parts[1] != b"200":
                 raise RuntimeError(f"Error response from Proxy server : 
{resp}")
 
+    def _is_socket_alive(self, sock):
+        """Check if a socket is still connected and alive.
+
+        Uses select() to check if socket is readable. An idle keep-alive socket
+        should NOT be readable.
+
+        Returns False if connection is closed or broken.
+        """
+        if sock is None:
+            return False
+        try:
+            # Proactive check: A closed socket has a fileno of -1.
+            if sock.fileno() < 0:
+                return False
+            # If the socket is readable while idle, it's either a FIN or dirty.
+            ready_to_read, _, _ = select.select([sock], [], [], 0.0)
+            if ready_to_read:
+                return False
+            
+            return True
+        except (OSError, ValueError, socket.error):
+            return False
+
     def get_socket(self):
         """get a socket from the pool. This blocks until one is available."""
         self._semaphore.acquire()
         if self._closed:
             raise RuntimeError("connection pool closed")
-        try:
-            return self._socket_queue.get(block=False)
-        except gevent.queue.Empty:
+
+        # Try to get a valid connection from the pool
+        while not self._socket_queue.empty():
             try:
-                return self._create_socket()
-            except:  # noqa
-                self._semaphore.release()
-                raise
+                sock = self._socket_queue.get(block=False)
+                if self._is_socket_alive(sock):
+                    # Connection is still alive, return it
+                    return sock
+                else:
+                    # Connection is dead, close it and try next
+                    try:
+                        sock.close()
+                    except:  # noqa
+                        pass
+            except gevent.queue.Empty:
+                break
+
+        # No valid connections in pool, create a new one
+        try:
+            return self._create_socket()
+        except:  # noqa
+            self._semaphore.release()
+            raise
 
     def return_socket(self, sock):
         """return a socket to the pool."""
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/geventhttpclient-2.3.7/tests/test_client.py 
new/geventhttpclient-2.3.9/tests/test_client.py
--- old/geventhttpclient-2.3.7/tests/test_client.py     2025-12-07 
19:55:26.000000000 +0100
+++ new/geventhttpclient-2.3.9/tests/test_client.py     2026-03-03 
08:31:41.000000000 +0100
@@ -1,4 +1,5 @@
 import json
+import socket
 
 import gevent.pool
 import gevent.queue
@@ -7,6 +8,7 @@
 
 from geventhttpclient import __version__
 from geventhttpclient.client import METHOD_GET, HTTPClient
+from geventhttpclient.connectionpool import ConnectionPool
 from tests.common import HTTPBIN_HOST, LISTENER, check_upload, server, 
wsgiserver
 
 
@@ -350,3 +352,32 @@
     assert count == 5
     # ensure at least 3 of requests got 200
     assert ok_count >= 3
+
+
+class TestIsSocketAlive:
+    """Unit tests for ConnectionPool._is_socket_alive()"""
+
+    def test_closed_socket_returns_false(self):
+        sock = socket.socket()
+        sock.close()
+        pool = ConnectionPool("127.0.0.1", 80, "127.0.0.1", 80)
+        assert sock.fileno() < 0
+        assert pool._is_socket_alive(sock) is False
+
+    def test_healthy_socket_returns_true(self):
+        s1, s2 = socket.socketpair()
+        try:
+            pool = ConnectionPool("127.0.0.1", 80, "127.0.0.1", 80)
+            assert pool._is_socket_alive(s1) is True
+        finally:
+            s1.close()
+            s2.close()
+
+    def test_peer_orderly_close_returns_false(self):
+        s1, s2 = socket.socketpair()
+        try:
+            s2.close()
+            pool = ConnectionPool("127.0.0.1", 80, "127.0.0.1", 80)
+            assert pool._is_socket_alive(s1) is False
+        finally:
+            s1.close()

Reply via email to