aboutsummaryrefslogtreecommitdiffstats
path: root/libmproxy/utils.py
diff options
context:
space:
mode:
Diffstat (limited to 'libmproxy/utils.py')
-rw-r--r--libmproxy/utils.py154
1 files changed, 56 insertions, 98 deletions
diff --git a/libmproxy/utils.py b/libmproxy/utils.py
index 8ac1f547..38fc6107 100644
--- a/libmproxy/utils.py
+++ b/libmproxy/utils.py
@@ -12,7 +12,7 @@
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-import re, os, subprocess, datetime, textwrap, errno, sys, time, functools
+import re, os, subprocess, datetime, textwrap, errno, sys, time, functools, copy
import json
CERT_SLEEP_TIME = 1
@@ -164,10 +164,6 @@ def isSequenceLike(anobj):
return 1
-def _caseless(s):
- return s.lower()
-
-
def try_del(dict, key):
try:
del dict[key]
@@ -175,108 +171,72 @@ def try_del(dict, key):
pass
-class MultiDict:
- """
- Simple wrapper around a dictionary to make holding multiple objects per
- key easier.
-
- Note that this class assumes that keys are strings.
-
- Keys have no order, but the order in which values are added to a key is
- preserved.
- """
- # This ridiculous bit of subterfuge is needed to prevent the class from
- # treating this as a bound method.
- _helper = (str,)
- def __init__(self):
- self._d = dict()
-
- def copy(self):
- m = self.__class__()
- m._d = self._d.copy()
- return m
-
- def clear(self):
- return self._d.clear()
-
- def get(self, key, d=None):
- key = self._helper[0](key)
- return self._d.get(key, d)
+class Headers:
+ def __init__(self, lst=None):
+ if lst:
+ self.lst = lst
+ else:
+ self.lst = []
- def __contains__(self, key):
- key = self._helper[0](key)
- return self._d.__contains__(key)
+ def _kconv(self, s):
+ return s.lower()
def __eq__(self, other):
- return dict(self) == dict(other)
-
- def __delitem__(self, key):
- self._d.__delitem__(key)
-
- def __getitem__(self, key):
- key = self._helper[0](key)
- return self._d.__getitem__(key)
-
- def __setitem__(self, key, value):
- if not isSequenceLike(value):
- raise ValueError, "Cannot insert non-sequence."
- key = self._helper[0](key)
- return self._d.__setitem__(key, value)
-
- def has_key(self, key):
- key = self._helper[0](key)
- return self._d.has_key(key)
-
- def setdefault(self, key, default=None):
- key = self._helper[0](key)
- return self._d.setdefault(key, default)
-
- def keys(self):
- return self._d.keys()
-
- def extend(self, key, value):
- if not self.has_key(key):
- self[key] = []
- self[key].extend(value)
+ return self.lst == other.lst
+
+ def __getitem__(self, k):
+ ret = []
+ k = self._kconv(k)
+ for i in self.lst:
+ if self._kconv(i[0]) == k:
+ ret.append(i[1])
+ return ret
+
+ def _filter_lst(self, k, lst):
+ new = []
+ for i in lst:
+ if self._kconv(i[0]) != k:
+ new.append(i)
+ return new
+
+ def __setitem__(self, k, hdrs):
+ k = self._kconv(k)
+ first = None
+ new = self._filter_lst(k, self.lst)
+ for i in hdrs:
+ new.append((k, i))
+ self.lst = new
+
+ def __delitem__(self, k):
+ self.lst = self._filter_lst(k, self.lst)
+
+ def __contains__(self, k):
+ for i in self.lst:
+ if self._kconv(i[0]) == k:
+ return True
+ return False
- def append(self, key, value):
- self.extend(key, [value])
-
- def itemPairs(self):
- """
- Yield all possible pairs of items.
- """
- for i in self.keys():
- for j in self[i]:
- yield (i, j)
+ def add(self, key, value):
+ self.lst.append([key, str(value)])
def get_state(self):
- return list(self.itemPairs())
+ return [tuple(i) for i in self.lst]
@classmethod
def from_state(klass, state):
- md = klass()
- for i in state:
- md.append(*i)
- return md
-
+ return klass([list(i) for i in state])
-class Headers(MultiDict):
- """
- A dictionary-like class for keeping track of HTTP headers.
+ def copy(self):
+ lst = copy.deepcopy(self.lst)
+ return Headers(lst)
- It is case insensitive, and __repr__ formats the headers correcty for
- output to the server.
- """
- _helper = (_caseless,)
def __repr__(self):
"""
Returns a string containing a formatted header string.
"""
headerElements = []
- for key in sorted(self.keys()):
- for val in self[key]:
- headerElements.append(key + ": " + val)
+ for itm in self.lst:
+ headerElements.append(itm[0] + ": " + itm[1])
headerElements.append("")
return "\r\n".join(headerElements)
@@ -284,7 +244,7 @@ class Headers(MultiDict):
"""
Match the regular expression against each header (key, value) pair.
"""
- for k, v in self.itemPairs():
+ for k, v in self.lst:
s = "%s: %s"%(k, v)
if re.search(expr, s):
return True
@@ -295,6 +255,7 @@ class Headers(MultiDict):
Read a set of headers from a file pointer. Stop once a blank line
is reached.
"""
+ ret = []
name = ''
while 1:
line = fp.readline()
@@ -302,18 +263,15 @@ class Headers(MultiDict):
break
if line[0] in ' \t':
# continued header
- self[name][-1] = self[name][-1] + '\r\n ' + line.strip()
+ ret[-1][1] = ret[-1][1] + '\r\n ' + line.strip()
else:
i = line.find(':')
# We're being liberal in what we accept, here.
if i > 0:
name = line[:i]
value = line[i+1:].strip()
- if self.has_key(name):
- # merge value
- self.append(name, value)
- else:
- self[name] = [value]
+ ret.append([name, value])
+ self.lst = ret
def pretty_size(size):