2019-05-08 13:47:52 +03:00
|
|
|
#!/usr/bin/env python
|
2012-07-30 13:21:32 +04:00
|
|
|
|
|
|
|
"""
|
2020-01-01 15:25:15 +03:00
|
|
|
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
|
2017-10-11 15:50:46 +03:00
|
|
|
See the file 'LICENSE' for copying permission
|
2012-07-30 13:21:32 +04:00
|
|
|
"""
|
|
|
|
|
2018-12-28 20:25:56 +03:00
|
|
|
import functools
|
2017-12-25 01:54:43 +03:00
|
|
|
import hashlib
|
2019-01-30 01:44:58 +03:00
|
|
|
import threading
|
2017-12-25 01:54:43 +03:00
|
|
|
|
2019-06-04 15:44:06 +03:00
|
|
|
from lib.core.datatype import LRUDict
|
2019-01-30 01:44:58 +03:00
|
|
|
from lib.core.settings import MAX_CACHE_ITEMS
|
2019-04-30 14:20:31 +03:00
|
|
|
from lib.core.settings import UNICODE_ENCODING
|
2018-04-01 13:45:47 +03:00
|
|
|
from lib.core.threads import getCurrentThreadData
|
|
|
|
|
2019-07-30 21:28:56 +03:00
|
|
|
_cache = {}
|
2019-07-18 15:59:42 +03:00
|
|
|
_cache_lock = threading.Lock()
|
|
|
|
_method_locks = {}
|
2019-01-30 01:44:58 +03:00
|
|
|
|
2019-07-30 21:28:56 +03:00
|
|
|
def cachedmethod(f):
|
2012-07-30 13:21:32 +04:00
|
|
|
"""
|
|
|
|
Method with a cached content
|
|
|
|
|
2019-05-06 15:41:35 +03:00
|
|
|
>>> __ = cachedmethod(lambda _: _)
|
|
|
|
>>> __(1)
|
|
|
|
1
|
|
|
|
>>> __ = cachedmethod(lambda *args, **kwargs: args[0])
|
|
|
|
>>> __(2)
|
|
|
|
2
|
2020-01-28 11:42:00 +03:00
|
|
|
>>> __ = cachedmethod(lambda *args, **kwargs: next(iter(kwargs.values())))
|
2019-05-06 15:41:35 +03:00
|
|
|
>>> __(foobar=3)
|
|
|
|
3
|
|
|
|
|
2012-07-30 13:21:32 +04:00
|
|
|
Reference: http://code.activestate.com/recipes/325205-cache-decorator-in-python-24/
|
|
|
|
"""
|
2013-01-30 13:38:11 +04:00
|
|
|
|
2019-07-30 21:28:56 +03:00
|
|
|
_cache[f] = LRUDict(capacity=MAX_CACHE_ITEMS)
|
|
|
|
|
2018-12-28 20:25:56 +03:00
|
|
|
@functools.wraps(f)
|
2019-07-30 21:28:56 +03:00
|
|
|
def _f(*args, **kwargs):
|
2019-02-10 01:18:08 +03:00
|
|
|
try:
|
2020-07-26 21:16:58 +03:00
|
|
|
key = int(hashlib.md5("|".join(str(_) for _ in (f, args, kwargs)).encode(UNICODE_ENCODING)).hexdigest(), 16) & 0x7fffffffffffffff
|
|
|
|
except ValueError: # https://github.com/sqlmapproject/sqlmap/issues/4281 (NOTE: non-standard Python behavior where hexdigest returns binary value)
|
2019-02-10 01:18:08 +03:00
|
|
|
result = f(*args, **kwargs)
|
2020-07-26 21:16:58 +03:00
|
|
|
else:
|
|
|
|
try:
|
|
|
|
with _cache_lock:
|
|
|
|
result = _cache[f][key]
|
|
|
|
except KeyError:
|
|
|
|
result = f(*args, **kwargs)
|
|
|
|
|
|
|
|
with _cache_lock:
|
|
|
|
_cache[f][key] = result
|
2019-02-10 01:18:08 +03:00
|
|
|
|
|
|
|
return result
|
2013-01-30 13:38:11 +04:00
|
|
|
|
2019-07-30 21:28:56 +03:00
|
|
|
return _f
|
2018-04-01 13:45:47 +03:00
|
|
|
|
|
|
|
def stackedmethod(f):
|
2018-12-28 20:25:56 +03:00
|
|
|
"""
|
|
|
|
Method using pushValue/popValue functions (fallback function for stack realignment)
|
2019-05-06 15:41:35 +03:00
|
|
|
|
|
|
|
>>> threadData = getCurrentThreadData()
|
|
|
|
>>> original = len(threadData.valueStack)
|
|
|
|
>>> __ = stackedmethod(lambda _: threadData.valueStack.append(_))
|
|
|
|
>>> __(1)
|
|
|
|
>>> len(threadData.valueStack) == original
|
|
|
|
True
|
2018-12-28 20:25:56 +03:00
|
|
|
"""
|
|
|
|
|
|
|
|
@functools.wraps(f)
|
2018-04-01 13:45:47 +03:00
|
|
|
def _(*args, **kwargs):
|
|
|
|
threadData = getCurrentThreadData()
|
|
|
|
originalLevel = len(threadData.valueStack)
|
|
|
|
|
|
|
|
try:
|
|
|
|
result = f(*args, **kwargs)
|
|
|
|
finally:
|
|
|
|
if len(threadData.valueStack) > originalLevel:
|
|
|
|
threadData.valueStack = threadData.valueStack[:originalLevel]
|
|
|
|
|
|
|
|
return result
|
|
|
|
|
2018-06-10 00:38:00 +03:00
|
|
|
return _
|
2019-07-18 15:59:42 +03:00
|
|
|
|
|
|
|
def lockedmethod(f):
|
|
|
|
@functools.wraps(f)
|
|
|
|
def _(*args, **kwargs):
|
|
|
|
if f not in _method_locks:
|
2019-08-11 02:32:20 +03:00
|
|
|
_method_locks[f] = threading.RLock()
|
2019-07-18 15:59:42 +03:00
|
|
|
|
|
|
|
with _method_locks[f]:
|
|
|
|
result = f(*args, **kwargs)
|
|
|
|
|
|
|
|
return result
|
|
|
|
|
|
|
|
return _
|