Minor patch

This commit is contained in:
Miroslav Štampar 2026-07-08 11:14:34 +02:00
parent 89ddc5a592
commit e2c55c1ddc
3 changed files with 32 additions and 5 deletions

View file

@ -20,7 +20,7 @@ from lib.core.enums import OS
from thirdparty import six
# sqlmap version (<major>.<minor>.<month>.<monthly commit>)
VERSION = "1.10.7.38"
VERSION = "1.10.7.39"
TYPE = "dev" if VERSION.count('.') > 2 and VERSION.split('.')[-1] != '0' else "stable"
TYPE_COLORS = {"dev": 33, "stable": 90, "pip": 34}
VERSION_STRING = "sqlmap/%s#%s" % ('.'.join(VERSION.split('.')[:-1]) if VERSION.count('.') > 2 and VERSION.split('.')[-1] == '0' else VERSION, TYPE)

View file

@ -760,6 +760,17 @@ class Connect(object):
warnMsg = "problem occurred during connection closing ('%s')" % getSafeExString(ex)
logger.warning(warnMsg)
# Keep-alive: dispose the response explicitly. Its wrapped close() hands the socket
# back to the pool when the body was fully drained, otherwise drops it (a size-capped
# partial read must not be reused). This avoids leaning on GC to reclaim it (delayed on
# non-refcounting runtimes like PyPy). Guarded by the handler's marker so the HTTP/2
# reuse pool is left untouched.
elif conn is not None and getattr(conn, "_keepaliveManaged", False):
try:
conn.close()
except Exception:
pass
except SqlmapConnectionException as ex:
if conf.proxyList and not kb.threadException:
warnMsg = "unable to connect to the target URL ('%s')" % getSafeExString(ex)

View file

@ -185,7 +185,11 @@ class _KeepAliveHandler(object):
a connection is never reused.
"""
state = {"handled": False}
# 'eof' is raised only on a genuine end-of-body (observed while reading), never
# merely because close() nulled the file object; the socket is handed back to the
# pool solely on that signal, so a half-read response can never be reused (which
# would splice its leftover bytes onto the next request - response desynchronization)
state = {"handled": False, "reading": False, "eof": False}
_read = response.read
_close = response.close
@ -200,7 +204,7 @@ class _KeepAliveHandler(object):
def settle():
# Once (and only once) the body is fully drained, decide the socket's fate
if state["handled"] or not drained():
if state["handled"] or not state["eof"]:
return
state["handled"] = True
if keep:
@ -212,12 +216,23 @@ class _KeepAliveHandler(object):
pass
def read(*args, **kwargs):
data = _read(*args, **kwargs)
state["reading"] = True
try:
data = _read(*args, **kwargs)
finally:
state["reading"] = False
if drained():
state["eof"] = True
settle()
return data
def close():
# Note: on Python 2 httplib.read() calls close() itself upon EOF
# Note: on Python 2 httplib.read() calls close() itself upon EOF, i.e. from inside
# our read(); such an in-read close marks a real end-of-body. An external close()
# on a not-yet-drained body means the caller abandoned it (e.g. sqlmap hitting a
# size cap), so the socket must be dropped rather than returned to the pool.
if state["reading"]:
state["eof"] = True
_close()
settle()
if not state["handled"]:
@ -228,6 +243,7 @@ class _KeepAliveHandler(object):
except Exception:
pass
response._keepaliveManaged = True
response.read = read
response.close = close