diff options
Diffstat (limited to 'libmproxy/utils.py')
-rw-r--r-- | libmproxy/utils.py | 80 |
1 files changed, 50 insertions, 30 deletions
diff --git a/libmproxy/utils.py b/libmproxy/utils.py index 51f2dc26..02e8403b 100644 --- a/libmproxy/utils.py +++ b/libmproxy/utils.py @@ -69,6 +69,33 @@ def urlencode(s): return urllib.urlencode(s, False) +def multipartdecode(hdrs, content): + """ + Takes a multipart boundary encoded string and returns list of (key, value) tuples. + """ + v = hdrs.get_first("content-type") + if v: + v = parse_content_type(v) + if not v: + return [] + boundary = v[2].get("boundary") + if not boundary: + return [] + + rx = re.compile(r'\bname="([^"]+)"') + r = [] + + for i in content.split("--" + boundary): + parts = i.splitlines() + if len(parts) > 1 and parts[0][0:2] != "--": + match = rx.search(parts[1]) + if match: + key = match.group(1) + value = "".join(parts[3+parts[2:].index(""):]) + r.append((key, value)) + return r + return [] + def pretty_size(size): suffixes = [ ("B", 2**10), @@ -119,40 +146,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): """ |