We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Headers aren't always case insensitive
Headers like `Content-Length` should preserve case after going trough mitmproxy, because some versions of PHP don't like lowercase headers (this is a server-side misimplementation of [RFC 2616](https://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2), but it would be nice if mitmproxy was able to handle this.).  

Steps to reproduce:
Capture some traffic, replay it with `mitmdump -nc capture_file`. Everything works as intended.
Now replay it, but use a script that replaces the request content. The `Content-Length` header get's changed to `content-lenght`.  

The problem probably lies at [netlib/http/message.py](https://github.com/mitmproxy/mitmproxy/blob/master/netlib/http/message.py#L104)
Mitmproxy Version: latest


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `netlib/multidict.py`
Content:
```
1 from __future__ import absolute_import, print_function, division
2 
3 from abc import ABCMeta, abstractmethod
4 
5 
6 try:
7     from collections.abc import MutableMapping
8 except ImportError:  # pragma: no cover
9     from collections import MutableMapping  # Workaround for Python < 3.3
10 
11 import six
12 from netlib import basetypes
13 
14 
15 @six.add_metaclass(ABCMeta)
16 class _MultiDict(MutableMapping, basetypes.Serializable):
17     def __repr__(self):
18         fields = (
19             repr(field)
20             for field in self.fields
21         )
22         return "{cls}[{fields}]".format(
23             cls=type(self).__name__,
24             fields=", ".join(fields)
25         )
26 
27     @staticmethod
28     @abstractmethod
29     def _reduce_values(values):
30         """
31         If a user accesses multidict["foo"], this method
32         reduces all values for "foo" to a single value that is returned.
33         For example, HTTP headers are folded, whereas we will just take
34         the first cookie we found with that name.
35         """
36 
37     @staticmethod
38     @abstractmethod
39     def _kconv(key):
40         """
41         This method converts a key to its canonical representation.
42         For example, HTTP headers are case-insensitive, so this method returns key.lower().
43         """
44 
45     def __getitem__(self, key):
46         values = self.get_all(key)
47         if not values:
48             raise KeyError(key)
49         return self._reduce_values(values)
50 
51     def __setitem__(self, key, value):
52         self.set_all(key, [value])
53 
54     def __delitem__(self, key):
55         if key not in self:
56             raise KeyError(key)
57         key = self._kconv(key)
58         self.fields = tuple(
59             field for field in self.fields
60             if key != self._kconv(field[0])
61         )
62 
63     def __iter__(self):
64         seen = set()
65         for key, _ in self.fields:
66             key_kconv = self._kconv(key)
67             if key_kconv not in seen:
68                 seen.add(key_kconv)
69                 yield key
70 
71     def __len__(self):
72         return len(set(self._kconv(key) for key, _ in self.fields))
73 
74     def __eq__(self, other):
75         if isinstance(other, MultiDict):
76             return self.fields == other.fields
77         return False
78 
79     def __ne__(self, other):
80         return not self.__eq__(other)
81 
82     def __hash__(self):
83         return hash(self.fields)
84 
85     def get_all(self, key):
86         """
87         Return the list of all values for a given key.
88         If that key is not in the MultiDict, the return value will be an empty list.
89         """
90         key = self._kconv(key)
91         return [
92             value
93             for k, value in self.fields
94             if self._kconv(k) == key
95         ]
96 
97     def set_all(self, key, values):
98         """
99         Remove the old values for a key and add new ones.
100         """
101         key_kconv = self._kconv(key)
102 
103         new_fields = []
104         for field in self.fields:
105             if self._kconv(field[0]) == key_kconv:
106                 if values:
107                     new_fields.append(
108                         (key, values.pop(0))
109                     )
110             else:
111                 new_fields.append(field)
112         while values:
113             new_fields.append(
114                 (key, values.pop(0))
115             )
116         self.fields = tuple(new_fields)
117 
118     def add(self, key, value):
119         """
120         Add an additional value for the given key at the bottom.
121         """
122         self.insert(len(self.fields), key, value)
123 
124     def insert(self, index, key, value):
125         """
126         Insert an additional value for the given key at the specified position.
127         """
128         item = (key, value)
129         self.fields = self.fields[:index] + (item,) + self.fields[index:]
130 
131     def keys(self, multi=False):
132         """
133         Get all keys.
134 
135         Args:
136             multi(bool):
137                 If True, one key per value will be returned.
138                 If False, duplicate keys will only be returned once.
139         """
140         return (
141             k
142             for k, _ in self.items(multi)
143         )
144 
145     def values(self, multi=False):
146         """
147         Get all values.
148 
149         Args:
150             multi(bool):
151                 If True, all values will be returned.
152                 If False, only the first value per key will be returned.
153         """
154         return (
155             v
156             for _, v in self.items(multi)
157         )
158 
159     def items(self, multi=False):
160         """
161         Get all (key, value) tuples.
162 
163         Args:
164             multi(bool):
165                 If True, all (key, value) pairs will be returned
166                 If False, only the first (key, value) pair per unique key will be returned.
167         """
168         if multi:
169             return self.fields
170         else:
171             return super(_MultiDict, self).items()
172 
173     def clear(self, key):
174         """
175             Removes all items with the specified key, and does not raise an
176             exception if the key does not exist.
177         """
178         if key in self:
179             del self[key]
180 
181     def collect(self):
182         """
183             Returns a list of (key, value) tuples, where values are either
184             singular if threre is only one matching item for a key, or a list
185             if there are more than one. The order of the keys matches the order
186             in the underlying fields list.
187         """
188         coll = []
189         for key in self:
190             values = self.get_all(key)
191             if len(values) == 1:
192                 coll.append([key, values[0]])
193             else:
194                 coll.append([key, values])
195         return coll
196 
197     def to_dict(self):
198         """
199         Get the MultiDict as a plain Python dict.
200         Keys with multiple values are returned as lists.
201 
202         Example:
203 
204         .. code-block:: python
205 
206             # Simple dict with duplicate values.
207             >>> d
208             MultiDictView[("name", "value"), ("a", "false"), ("a", "42")]
209             >>> d.to_dict()
210             {
211                 "name": "value",
212                 "a": ["false", "42"]
213             }
214         """
215         d = {}
216         for k, v in self.collect():
217             d[k] = v
218         return d
219 
220     def get_state(self):
221         return self.fields
222 
223     def set_state(self, state):
224         self.fields = tuple(tuple(x) for x in state)
225 
226     @classmethod
227     def from_state(cls, state):
228         return cls(state)
229 
230 
231 class MultiDict(_MultiDict):
232     def __init__(self, fields=()):
233         super(MultiDict, self).__init__()
234         self.fields = tuple(
235             tuple(i) for i in fields
236         )
237 
238 
239 @six.add_metaclass(ABCMeta)
240 class ImmutableMultiDict(MultiDict):
241     def _immutable(self, *_):
242         raise TypeError('{} objects are immutable'.format(self.__class__.__name__))
243 
244     __delitem__ = set_all = insert = _immutable
245 
246     def with_delitem(self, key):
247         """
248         Returns:
249             An updated ImmutableMultiDict. The original object will not be modified.
250         """
251         ret = self.copy()
252         super(ImmutableMultiDict, ret).__delitem__(key)
253         return ret
254 
255     def with_set_all(self, key, values):
256         """
257         Returns:
258             An updated ImmutableMultiDict. The original object will not be modified.
259         """
260         ret = self.copy()
261         super(ImmutableMultiDict, ret).set_all(key, values)
262         return ret
263 
264     def with_insert(self, index, key, value):
265         """
266         Returns:
267             An updated ImmutableMultiDict. The original object will not be modified.
268         """
269         ret = self.copy()
270         super(ImmutableMultiDict, ret).insert(index, key, value)
271         return ret
272 
273 
274 class MultiDictView(_MultiDict):
275     """
276     The MultiDictView provides the MultiDict interface over calculated data.
277     The view itself contains no state - data is retrieved from the parent on
278     request, and stored back to the parent on change.
279     """
280     def __init__(self, getter, setter):
281         self._getter = getter
282         self._setter = setter
283         super(MultiDictView, self).__init__()
284 
285     @staticmethod
286     def _kconv(key):
287         # All request-attributes are case-sensitive.
288         return key
289 
290     @staticmethod
291     def _reduce_values(values):
292         # We just return the first element if
293         # multiple elements exist with the same key.
294         return values[0]
295 
296     @property
297     def fields(self):
298         return self._getter()
299 
300     @fields.setter
301     def fields(self, value):
302         return self._setter(value)
303
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/netlib/multidict.py b/netlib/multidict.py
--- a/netlib/multidict.py
+++ b/netlib/multidict.py
@@ -105,7 +105,7 @@
             if self._kconv(field[0]) == key_kconv:
                 if values:
                     new_fields.append(
-                        (key, values.pop(0))
+                        (field[0], values.pop(0))
                     )
             else:
                 new_fields.append(field)

{"golden_diff": "diff --git a/netlib/multidict.py b/netlib/multidict.py\n--- a/netlib/multidict.py\n+++ b/netlib/multidict.py\n@@ -105,7 +105,7 @@\n             if self._kconv(field[0]) == key_kconv:\n                 if values:\n                     new_fields.append(\n-                        (key, values.pop(0))\n+                        (field[0], values.pop(0))\n                     )\n             else:\n                 new_fields.append(field)\n", "issue": "Headers aren't always case insensitive\nHeaders like `Content-Length` should preserve case after going trough mitmproxy, because some versions of PHP don't like lowercase headers (this is a server-side misimplementation of [RFC 2616](https://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2), but it would be nice if mitmproxy was able to handle this.).  \n\nSteps to reproduce:\nCapture some traffic, replay it with `mitmdump -nc capture_file`. Everything works as intended.\nNow replay it, but use a script that replaces the request content. The `Content-Length` header get's changed to `content-lenght`.  \n\nThe problem probably lies at [netlib/http/message.py](https://github.com/mitmproxy/mitmproxy/blob/master/netlib/http/message.py#L104)\nMitmproxy Version: latest\n\n", "before_files": [{"content": "from __future__ import absolute_import, print_function, division\n\nfrom abc import ABCMeta, abstractmethod\n\n\ntry:\n    from collections.abc import MutableMapping\nexcept ImportError:  # pragma: no cover\n    from collections import MutableMapping  # Workaround for Python < 3.3\n\nimport six\nfrom netlib import basetypes\n\n\n@six.add_metaclass(ABCMeta)\nclass _MultiDict(MutableMapping, basetypes.Serializable):\n    def __repr__(self):\n        fields = (\n            repr(field)\n            for field in self.fields\n        )\n        return \"{cls}[{fields}]\".format(\n            cls=type(self).__name__,\n            fields=\", \".join(fields)\n        )\n\n    @staticmethod\n    @abstractmethod\n    def _reduce_values(values):\n        \"\"\"\n        If a user accesses multidict[\"foo\"], this method\n        reduces all values for \"foo\" to a single value that is returned.\n        For example, HTTP headers are folded, whereas we will just take\n        the first cookie we found with that name.\n        \"\"\"\n\n    @staticmethod\n    @abstractmethod\n    def _kconv(key):\n        \"\"\"\n        This method converts a key to its canonical representation.\n        For example, HTTP headers are case-insensitive, so this method returns key.lower().\n        \"\"\"\n\n    def __getitem__(self, key):\n        values = self.get_all(key)\n        if not values:\n            raise KeyError(key)\n        return self._reduce_values(values)\n\n    def __setitem__(self, key, value):\n        self.set_all(key, [value])\n\n    def __delitem__(self, key):\n        if key not in self:\n            raise KeyError(key)\n        key = self._kconv(key)\n        self.fields = tuple(\n            field for field in self.fields\n            if key != self._kconv(field[0])\n        )\n\n    def __iter__(self):\n        seen = set()\n        for key, _ in self.fields:\n            key_kconv = self._kconv(key)\n            if key_kconv not in seen:\n                seen.add(key_kconv)\n                yield key\n\n    def __len__(self):\n        return len(set(self._kconv(key) for key, _ in self.fields))\n\n    def __eq__(self, other):\n        if isinstance(other, MultiDict):\n            return self.fields == other.fields\n        return False\n\n    def __ne__(self, other):\n        return not self.__eq__(other)\n\n    def __hash__(self):\n        return hash(self.fields)\n\n    def get_all(self, key):\n        \"\"\"\n        Return the list of all values for a given key.\n        If that key is not in the MultiDict, the return value will be an empty list.\n        \"\"\"\n        key = self._kconv(key)\n        return [\n            value\n            for k, value in self.fields\n            if self._kconv(k) == key\n        ]\n\n    def set_all(self, key, values):\n        \"\"\"\n        Remove the old values for a key and add new ones.\n        \"\"\"\n        key_kconv = self._kconv(key)\n\n        new_fields = []\n        for field in self.fields:\n            if self._kconv(field[0]) == key_kconv:\n                if values:\n                    new_fields.append(\n                        (key, values.pop(0))\n                    )\n            else:\n                new_fields.append(field)\n        while values:\n            new_fields.append(\n                (key, values.pop(0))\n            )\n        self.fields = tuple(new_fields)\n\n    def add(self, key, value):\n        \"\"\"\n        Add an additional value for the given key at the bottom.\n        \"\"\"\n        self.insert(len(self.fields), key, value)\n\n    def insert(self, index, key, value):\n        \"\"\"\n        Insert an additional value for the given key at the specified position.\n        \"\"\"\n        item = (key, value)\n        self.fields = self.fields[:index] + (item,) + self.fields[index:]\n\n    def keys(self, multi=False):\n        \"\"\"\n        Get all keys.\n\n        Args:\n            multi(bool):\n                If True, one key per value will be returned.\n                If False, duplicate keys will only be returned once.\n        \"\"\"\n        return (\n            k\n            for k, _ in self.items(multi)\n        )\n\n    def values(self, multi=False):\n        \"\"\"\n        Get all values.\n\n        Args:\n            multi(bool):\n                If True, all values will be returned.\n                If False, only the first value per key will be returned.\n        \"\"\"\n        return (\n            v\n            for _, v in self.items(multi)\n        )\n\n    def items(self, multi=False):\n        \"\"\"\n        Get all (key, value) tuples.\n\n        Args:\n            multi(bool):\n                If True, all (key, value) pairs will be returned\n                If False, only the first (key, value) pair per unique key will be returned.\n        \"\"\"\n        if multi:\n            return self.fields\n        else:\n            return super(_MultiDict, self).items()\n\n    def clear(self, key):\n        \"\"\"\n            Removes all items with the specified key, and does not raise an\n            exception if the key does not exist.\n        \"\"\"\n        if key in self:\n            del self[key]\n\n    def collect(self):\n        \"\"\"\n            Returns a list of (key, value) tuples, where values are either\n            singular if threre is only one matching item for a key, or a list\n            if there are more than one. The order of the keys matches the order\n            in the underlying fields list.\n        \"\"\"\n        coll = []\n        for key in self:\n            values = self.get_all(key)\n            if len(values) == 1:\n                coll.append([key, values[0]])\n            else:\n                coll.append([key, values])\n        return coll\n\n    def to_dict(self):\n        \"\"\"\n        Get the MultiDict as a plain Python dict.\n        Keys with multiple values are returned as lists.\n\n        Example:\n\n        .. code-block:: python\n\n            # Simple dict with duplicate values.\n            >>> d\n            MultiDictView[(\"name\", \"value\"), (\"a\", \"false\"), (\"a\", \"42\")]\n            >>> d.to_dict()\n            {\n                \"name\": \"value\",\n                \"a\": [\"false\", \"42\"]\n            }\n        \"\"\"\n        d = {}\n        for k, v in self.collect():\n            d[k] = v\n        return d\n\n    def get_state(self):\n        return self.fields\n\n    def set_state(self, state):\n        self.fields = tuple(tuple(x) for x in state)\n\n    @classmethod\n    def from_state(cls, state):\n        return cls(state)\n\n\nclass MultiDict(_MultiDict):\n    def __init__(self, fields=()):\n        super(MultiDict, self).__init__()\n        self.fields = tuple(\n            tuple(i) for i in fields\n        )\n\n\n@six.add_metaclass(ABCMeta)\nclass ImmutableMultiDict(MultiDict):\n    def _immutable(self, *_):\n        raise TypeError('{} objects are immutable'.format(self.__class__.__name__))\n\n    __delitem__ = set_all = insert = _immutable\n\n    def with_delitem(self, key):\n        \"\"\"\n        Returns:\n            An updated ImmutableMultiDict. The original object will not be modified.\n        \"\"\"\n        ret = self.copy()\n        super(ImmutableMultiDict, ret).__delitem__(key)\n        return ret\n\n    def with_set_all(self, key, values):\n        \"\"\"\n        Returns:\n            An updated ImmutableMultiDict. The original object will not be modified.\n        \"\"\"\n        ret = self.copy()\n        super(ImmutableMultiDict, ret).set_all(key, values)\n        return ret\n\n    def with_insert(self, index, key, value):\n        \"\"\"\n        Returns:\n            An updated ImmutableMultiDict. The original object will not be modified.\n        \"\"\"\n        ret = self.copy()\n        super(ImmutableMultiDict, ret).insert(index, key, value)\n        return ret\n\n\nclass MultiDictView(_MultiDict):\n    \"\"\"\n    The MultiDictView provides the MultiDict interface over calculated data.\n    The view itself contains no state - data is retrieved from the parent on\n    request, and stored back to the parent on change.\n    \"\"\"\n    def __init__(self, getter, setter):\n        self._getter = getter\n        self._setter = setter\n        super(MultiDictView, self).__init__()\n\n    @staticmethod\n    def _kconv(key):\n        # All request-attributes are case-sensitive.\n        return key\n\n    @staticmethod\n    def _reduce_values(values):\n        # We just return the first element if\n        # multiple elements exist with the same key.\n        return values[0]\n\n    @property\n    def fields(self):\n        return self._getter()\n\n    @fields.setter\n    def fields(self, value):\n        return self._setter(value)\n", "path": "netlib/multidict.py"}], "after_files": [{"content": "from __future__ import absolute_import, print_function, division\n\nfrom abc import ABCMeta, abstractmethod\n\n\ntry:\n    from collections.abc import MutableMapping\nexcept ImportError:  # pragma: no cover\n    from collections import MutableMapping  # Workaround for Python < 3.3\n\nimport six\nfrom netlib import basetypes\n\n\n@six.add_metaclass(ABCMeta)\nclass _MultiDict(MutableMapping, basetypes.Serializable):\n    def __repr__(self):\n        fields = (\n            repr(field)\n            for field in self.fields\n        )\n        return \"{cls}[{fields}]\".format(\n            cls=type(self).__name__,\n            fields=\", \".join(fields)\n        )\n\n    @staticmethod\n    @abstractmethod\n    def _reduce_values(values):\n        \"\"\"\n        If a user accesses multidict[\"foo\"], this method\n        reduces all values for \"foo\" to a single value that is returned.\n        For example, HTTP headers are folded, whereas we will just take\n        the first cookie we found with that name.\n        \"\"\"\n\n    @staticmethod\n    @abstractmethod\n    def _kconv(key):\n        \"\"\"\n        This method converts a key to its canonical representation.\n        For example, HTTP headers are case-insensitive, so this method returns key.lower().\n        \"\"\"\n\n    def __getitem__(self, key):\n        values = self.get_all(key)\n        if not values:\n            raise KeyError(key)\n        return self._reduce_values(values)\n\n    def __setitem__(self, key, value):\n        self.set_all(key, [value])\n\n    def __delitem__(self, key):\n        if key not in self:\n            raise KeyError(key)\n        key = self._kconv(key)\n        self.fields = tuple(\n            field for field in self.fields\n            if key != self._kconv(field[0])\n        )\n\n    def __iter__(self):\n        seen = set()\n        for key, _ in self.fields:\n            key_kconv = self._kconv(key)\n            if key_kconv not in seen:\n                seen.add(key_kconv)\n                yield key\n\n    def __len__(self):\n        return len(set(self._kconv(key) for key, _ in self.fields))\n\n    def __eq__(self, other):\n        if isinstance(other, MultiDict):\n            return self.fields == other.fields\n        return False\n\n    def __ne__(self, other):\n        return not self.__eq__(other)\n\n    def __hash__(self):\n        return hash(self.fields)\n\n    def get_all(self, key):\n        \"\"\"\n        Return the list of all values for a given key.\n        If that key is not in the MultiDict, the return value will be an empty list.\n        \"\"\"\n        key = self._kconv(key)\n        return [\n            value\n            for k, value in self.fields\n            if self._kconv(k) == key\n        ]\n\n    def set_all(self, key, values):\n        \"\"\"\n        Remove the old values for a key and add new ones.\n        \"\"\"\n        key_kconv = self._kconv(key)\n\n        new_fields = []\n        for field in self.fields:\n            if self._kconv(field[0]) == key_kconv:\n                if values:\n                    new_fields.append(\n                        (field[0], values.pop(0))\n                    )\n            else:\n                new_fields.append(field)\n        while values:\n            new_fields.append(\n                (key, values.pop(0))\n            )\n        self.fields = tuple(new_fields)\n\n    def add(self, key, value):\n        \"\"\"\n        Add an additional value for the given key at the bottom.\n        \"\"\"\n        self.insert(len(self.fields), key, value)\n\n    def insert(self, index, key, value):\n        \"\"\"\n        Insert an additional value for the given key at the specified position.\n        \"\"\"\n        item = (key, value)\n        self.fields = self.fields[:index] + (item,) + self.fields[index:]\n\n    def keys(self, multi=False):\n        \"\"\"\n        Get all keys.\n\n        Args:\n            multi(bool):\n                If True, one key per value will be returned.\n                If False, duplicate keys will only be returned once.\n        \"\"\"\n        return (\n            k\n            for k, _ in self.items(multi)\n        )\n\n    def values(self, multi=False):\n        \"\"\"\n        Get all values.\n\n        Args:\n            multi(bool):\n                If True, all values will be returned.\n                If False, only the first value per key will be returned.\n        \"\"\"\n        return (\n            v\n            for _, v in self.items(multi)\n        )\n\n    def items(self, multi=False):\n        \"\"\"\n        Get all (key, value) tuples.\n\n        Args:\n            multi(bool):\n                If True, all (key, value) pairs will be returned\n                If False, only the first (key, value) pair per unique key will be returned.\n        \"\"\"\n        if multi:\n            return self.fields\n        else:\n            return super(_MultiDict, self).items()\n\n    def clear(self, key):\n        \"\"\"\n            Removes all items with the specified key, and does not raise an\n            exception if the key does not exist.\n        \"\"\"\n        if key in self:\n            del self[key]\n\n    def collect(self):\n        \"\"\"\n            Returns a list of (key, value) tuples, where values are either\n            singular if threre is only one matching item for a key, or a list\n            if there are more than one. The order of the keys matches the order\n            in the underlying fields list.\n        \"\"\"\n        coll = []\n        for key in self:\n            values = self.get_all(key)\n            if len(values) == 1:\n                coll.append([key, values[0]])\n            else:\n                coll.append([key, values])\n        return coll\n\n    def to_dict(self):\n        \"\"\"\n        Get the MultiDict as a plain Python dict.\n        Keys with multiple values are returned as lists.\n\n        Example:\n\n        .. code-block:: python\n\n            # Simple dict with duplicate values.\n            >>> d\n            MultiDictView[(\"name\", \"value\"), (\"a\", \"false\"), (\"a\", \"42\")]\n            >>> d.to_dict()\n            {\n                \"name\": \"value\",\n                \"a\": [\"false\", \"42\"]\n            }\n        \"\"\"\n        d = {}\n        for k, v in self.collect():\n            d[k] = v\n        return d\n\n    def get_state(self):\n        return self.fields\n\n    def set_state(self, state):\n        self.fields = tuple(tuple(x) for x in state)\n\n    @classmethod\n    def from_state(cls, state):\n        return cls(state)\n\n\nclass MultiDict(_MultiDict):\n    def __init__(self, fields=()):\n        super(MultiDict, self).__init__()\n        self.fields = tuple(\n            tuple(i) for i in fields\n        )\n\n\n@six.add_metaclass(ABCMeta)\nclass ImmutableMultiDict(MultiDict):\n    def _immutable(self, *_):\n        raise TypeError('{} objects are immutable'.format(self.__class__.__name__))\n\n    __delitem__ = set_all = insert = _immutable\n\n    def with_delitem(self, key):\n        \"\"\"\n        Returns:\n            An updated ImmutableMultiDict. The original object will not be modified.\n        \"\"\"\n        ret = self.copy()\n        super(ImmutableMultiDict, ret).__delitem__(key)\n        return ret\n\n    def with_set_all(self, key, values):\n        \"\"\"\n        Returns:\n            An updated ImmutableMultiDict. The original object will not be modified.\n        \"\"\"\n        ret = self.copy()\n        super(ImmutableMultiDict, ret).set_all(key, values)\n        return ret\n\n    def with_insert(self, index, key, value):\n        \"\"\"\n        Returns:\n            An updated ImmutableMultiDict. The original object will not be modified.\n        \"\"\"\n        ret = self.copy()\n        super(ImmutableMultiDict, ret).insert(index, key, value)\n        return ret\n\n\nclass MultiDictView(_MultiDict):\n    \"\"\"\n    The MultiDictView provides the MultiDict interface over calculated data.\n    The view itself contains no state - data is retrieved from the parent on\n    request, and stored back to the parent on change.\n    \"\"\"\n    def __init__(self, getter, setter):\n        self._getter = getter\n        self._setter = setter\n        super(MultiDictView, self).__init__()\n\n    @staticmethod\n    def _kconv(key):\n        # All request-attributes are case-sensitive.\n        return key\n\n    @staticmethod\n    def _reduce_values(values):\n        # We just return the first element if\n        # multiple elements exist with the same key.\n        return values[0]\n\n    @property\n    def fields(self):\n        return self._getter()\n\n    @fields.setter\n    def fields(self, value):\n        return self._setter(value)\n", "path": "netlib/multidict.py"}]}