diff options
| author | Aldo Cortesi <aldo@nullcube.com> | 2015-03-22 21:00:41 +1300 | 
|---|---|---|
| committer | Aldo Cortesi <aldo@nullcube.com> | 2015-03-22 21:00:41 +1300 | 
| commit | 842e23d3e386169d9a90cef2a634c55a3e5fdd8e (patch) | |
| tree | 4932fa82faf92d36fbe7a8d56741a892c7003119 | |
| parent | a2da38cc8339887abef4efa23cc54fa02c981f3f (diff) | |
| download | mitmproxy-842e23d3e386169d9a90cef2a634c55a3e5fdd8e.tar.gz mitmproxy-842e23d3e386169d9a90cef2a634c55a3e5fdd8e.tar.bz2 mitmproxy-842e23d3e386169d9a90cef2a634c55a3e5fdd8e.zip  | |
Replace far-too-clever decorator LRU cache with something simpler
| -rw-r--r-- | libmproxy/console/common.py | 9 | ||||
| -rw-r--r-- | libmproxy/console/flowview.py | 15 | ||||
| -rw-r--r-- | libmproxy/utils.py | 53 | ||||
| -rw-r--r-- | test/test_utils.py | 26 | ||||
| -rwxr-xr-x | test/tools/testpatt | 10 | 
5 files changed, 47 insertions, 66 deletions
diff --git a/libmproxy/console/common.py b/libmproxy/console/common.py index a0590bb1..2f143f01 100644 --- a/libmproxy/console/common.py +++ b/libmproxy/console/common.py @@ -327,11 +327,7 @@ def ask_save_body(part, master, state, flow):          signals.status_message.send(message="No content to save.") -class FlowCache: -    @utils.LRUCache(200) -    def format_flow(self, *args): -        return raw_format_flow(*args) -flowcache = FlowCache() +flowcache = utils.LRUCache(800)  def format_flow(f, focus, extended=False, hostheader=False, padding=2): @@ -370,6 +366,7 @@ def format_flow(f, focus, extended=False, hostheader=False, padding=2):              d["resp_ctype"] = t[0].split(";")[0]          else:              d["resp_ctype"] = "" -    return flowcache.format_flow( +    return flowcache.get( +        raw_format_flow,          tuple(sorted(d.items())), focus, extended, padding      ) diff --git a/libmproxy/console/flowview.py b/libmproxy/console/flowview.py index e864cf47..2c847fba 100644 --- a/libmproxy/console/flowview.py +++ b/libmproxy/console/flowview.py @@ -107,16 +107,7 @@ class FlowViewHeader(urwid.WidgetWrap):              ) -class CallbackCache: -    @utils.LRUCache(200) -    def _callback(self, method, *args, **kwargs): -        return getattr(self.obj, method)(*args, **kwargs) - -    def callback(self, obj, method, *args, **kwargs): -        # obj varies! -        self.obj = obj -        return self._callback(method, *args, **kwargs) -cache = CallbackCache() +cache = utils.LRUCache(200)  class FlowView(urwid.WidgetWrap): @@ -158,8 +149,8 @@ class FlowView(urwid.WidgetWrap):              limit = sys.maxint          else:              limit = contentview.VIEW_CUTOFF -        description, text_objects = cache.callback( -                    self, "_cached_content_view", +        description, text_objects = cache.get( +                    self._cached_content_view,                      viewmode,                      tuple(tuple(i) for i in conn.headers.lst),                      conn.content, diff --git a/libmproxy/utils.py b/libmproxy/utils.py index 51f2dc26..5ed70a45 100644 --- a/libmproxy/utils.py +++ b/libmproxy/utils.py @@ -119,40 +119,33 @@ pkg_data = Data(__name__)  class LRUCache:      """ -        A decorator that implements a self-expiring LRU cache for class -        methods (not functions!). - -        Cache data is tracked as attributes on the object itself. There is -        therefore a separate cache for each object instance. +        A simple LRU cache for generated values.      """      def __init__(self, size=100):          self.size = size +        self.cache = {} +        self.cacheList  = [] + +    def get(self, gen, *args): +        """ +            gen: A (presumably expensive) generator function. The identity of +            gen is NOT taken into account by the cache. +            *args: A list of immutable arguments, used to establish identiy by +            *the cache, and passed to gen to generate values. +        """ +        if self.cache.has_key(args): +            self.cacheList.remove(args) +            self.cacheList.insert(0, args) +            return self.cache[args] +        else: +            ret = gen(*args) +            self.cacheList.insert(0, args) +            self.cache[args] = ret +            if len(self.cacheList) > self.size: +                d = self.cacheList.pop() +                self.cache.pop(d) +            return ret -    def __call__(self, f): -        cacheName = "_cached_%s"%f.__name__ -        cacheListName = "_cachelist_%s"%f.__name__ -        size = self.size - -        @functools.wraps(f) -        def wrap(self, *args): -            if not hasattr(self, cacheName): -                setattr(self, cacheName, {}) -                setattr(self, cacheListName, []) -            cache = getattr(self, cacheName) -            cacheList = getattr(self, cacheListName) -            if cache.has_key(args): -                cacheList.remove(args) -                cacheList.insert(0, args) -                return cache[args] -            else: -                ret = f(self, *args) -                cacheList.insert(0, args) -                cache[args] = ret -                if len(cacheList) > size: -                    d = cacheList.pop() -                    cache.pop(d) -                return ret -        return wrap  def parse_content_type(c):      """ diff --git a/test/test_utils.py b/test/test_utils.py index 78d1c072..1678a7de 100644 --- a/test/test_utils.py +++ b/test/test_utils.py @@ -62,38 +62,39 @@ def test_pretty_duration():      assert utils.pretty_duration(10) == "10.0s"      assert utils.pretty_duration(100) == "100s"      assert utils.pretty_duration(1000) == "1000s" -    assert utils.pretty_duration(10000) == "10000s"     +    assert utils.pretty_duration(10000) == "10000s"      assert utils.pretty_duration(1.123) == "1.12s"      assert utils.pretty_duration(0.123) == "123ms"  def test_LRUCache(): +    cache = utils.LRUCache(2)      class Foo:          ran = False -        @utils.LRUCache(2) -        def one(self, x): +        def gen(self, x):              self.ran = True              return x -      f = Foo() -    assert f.one(1) == 1 + +    assert not f.ran +    assert cache.get(f.gen, 1) == 1      assert f.ran      f.ran = False -    assert f.one(1) == 1 +    assert cache.get(f.gen, 1) == 1      assert not f.ran      f.ran = False -    assert f.one(1) == 1 +    assert cache.get(f.gen, 1) == 1      assert not f.ran -    assert f.one(2) == 2 -    assert f.one(3) == 3 +    assert cache.get(f.gen, 2) == 2 +    assert cache.get(f.gen, 3) == 3      assert f.ran      f.ran = False -    assert f.one(1) == 1 +    assert cache.get(f.gen, 1) == 1      assert f.ran -    assert len(f._cached_one) == 2 -    assert len(f._cachelist_one) == 2 +    assert len(cache.cacheList) == 2 +    assert len(cache.cache) == 2  def test_unparse_url(): @@ -128,4 +129,3 @@ def test_safe_subn():  def test_urlencode():      assert utils.urlencode([('foo','bar')]) - diff --git a/test/tools/testpatt b/test/tools/testpatt index d4546d48..5ee1ea02 100755 --- a/test/tools/testpatt +++ b/test/tools/testpatt @@ -2,8 +2,8 @@  # Generate a test pattern with pathoc  PATHOD=http://localhost:9999 -pathoc localhost:8080 "get:'$PATHOD/p/200:p0,1:b@200b':b@200b" -pathoc localhost:8080 "get:'$PATHOD/p/300:p0,1:b@200b':b@200b" -pathoc localhost:8080 "get:'$PATHOD/p/400:p0,1:b@200b':b@200b" -pathoc localhost:8080 "get:'$PATHOD/p/500:p0,1:b@200b':b@200b" -pathoc localhost:8080 "get:'$PATHOD/p/600:p0,1:b@200b':b@200b" +pathoc localhost:8080 "get:'$PATHOD/p/200:p0,1:b@2048b':b@2048b" +pathoc localhost:8080 "get:'$PATHOD/p/300:p0,1:b@2048b':b@2048b" +pathoc localhost:8080 "get:'$PATHOD/p/400:p0,1:b@2048b':b@2048b" +pathoc localhost:8080 "get:'$PATHOD/p/500:p0,1:b@2048b':b@2048b" +pathoc localhost:8080 "get:'$PATHOD/p/600:p0,1:b@2048b':b@2048b"  | 
