We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Cookie totally breaks if the client sets a bare cookie
### Is there an existing issue for this?

- [X] I have searched the existing issues

### Describe the bug

A cookie may be not in the `key=value` format. For example. if the JS code runs `document.cookie = "bad"`, it becomes:

![image](https://github.com/sanic-org/sanic/assets/6646473/c9a1f53c-62bf-4516-9003-49fed08773dc)

I don't know how to call it. I will use the term "bare cookie" in this report. In the following requests with a bare cookie, the Cookie HTTP header becomes: `Cookie: key=value; bad`

![image](https://github.com/sanic-org/sanic/assets/6646473/536bdf38-61ad-4f31-bb78-6c7844433298)

It seems that Sanic cannot parse the header with bare cookies, and will throw all cookies (including the legimit `key=value` pair) away. See the code snippet below.

### Code snippet

```python
from sanic import Sanic
from sanic.response import html, text

app = Sanic("test")
app.config.AUTO_EXTEND = False

@app.get("/")
async def route1(request):
    return html('<script>document.cookie="key=value"; document.cookie="bad"; location.href="/fire";</script>')
    
@app.get("/fire")
async def route2(request):
    return text(f'''
        headers = {request.headers.get("Cookie")}
        key = {request.cookies.get("key", "none")}
    ''')

if __name__ == '__main__':
    app.run(port=4321, debug=True)
```

Then visit `http://127.0.0.1:4321/` in Chrome. The page shows:

```
headers = key=value; bad
key = none
```

### Expected Behavior

The page should show:

```
headers = key=value; bad
key = value
```

### How do you run Sanic?

As a script (`app.run` or `Sanic.serve`)

### Operating System

Windows

### Sanic Version

22.12.0

### Additional context

I am using the latest stable Chrome (117.0.5938.150) to reproduce this.




--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `sanic/models/protocol_types.py`
Content:
```
1 from __future__ import annotations
2 
3 import sys
4 
5 from asyncio import BaseTransport
6 from typing import TYPE_CHECKING, Any, AnyStr, Optional
7 
8 
9 if TYPE_CHECKING:
10     from sanic.http.constants import HTTP
11     from sanic.models.asgi import ASGIScope
12 
13 
14 if sys.version_info < (3, 8):
15     Range = Any
16     HTMLProtocol = Any
17 else:
18     # Protocol is a 3.8+ feature
19     from typing import Protocol
20 
21     class HTMLProtocol(Protocol):
22         def __html__(self) -> AnyStr:
23             ...
24 
25         def _repr_html_(self) -> AnyStr:
26             ...
27 
28     class Range(Protocol):
29         start: Optional[int]
30         end: Optional[int]
31         size: Optional[int]
32         total: Optional[int]
33         __slots__ = ()
34 
35 
36 class TransportProtocol(BaseTransport):
37     scope: ASGIScope
38     version: HTTP
39     __slots__ = ()
40
```

Path: `sanic/cookies/request.py`
Content:
```
1 import re
2 
3 from typing import Any, Dict, List, Optional
4 
5 from sanic.cookies.response import Cookie
6 from sanic.log import deprecation
7 from sanic.request.parameters import RequestParameters
8 
9 
10 COOKIE_NAME_RESERVED_CHARS = re.compile(
11     '[\x00-\x1F\x7F-\xFF()<>@,;:\\\\"/[\\]?={} \x09]'
12 )
13 OCTAL_PATTERN = re.compile(r"\\[0-3][0-7][0-7]")
14 QUOTE_PATTERN = re.compile(r"[\\].")
15 
16 
17 def _unquote(str):  # no cov
18     if str is None or len(str) < 2:
19         return str
20     if str[0] != '"' or str[-1] != '"':
21         return str
22 
23     str = str[1:-1]
24 
25     i = 0
26     n = len(str)
27     res = []
28     while 0 <= i < n:
29         o_match = OCTAL_PATTERN.search(str, i)
30         q_match = QUOTE_PATTERN.search(str, i)
31         if not o_match and not q_match:
32             res.append(str[i:])
33             break
34         # else:
35         j = k = -1
36         if o_match:
37             j = o_match.start(0)
38         if q_match:
39             k = q_match.start(0)
40         if q_match and (not o_match or k < j):
41             res.append(str[i:k])
42             res.append(str[k + 1])
43             i = k + 2
44         else:
45             res.append(str[i:j])
46             res.append(chr(int(str[j + 1 : j + 4], 8)))  # noqa: E203
47             i = j + 4
48     return "".join(res)
49 
50 
51 def parse_cookie(raw: str) -> Dict[str, List[str]]:
52     """Parses a raw cookie string into a dictionary.
53 
54     The function takes a raw cookie string (usually from HTTP headers) and
55     returns a dictionary where each key is a cookie name and the value is a
56     list of values for that cookie. The function handles quoted values and
57     skips invalid cookie names.
58 
59     Args:
60         raw (str): The raw cookie string to be parsed.
61 
62     Returns:
63         Dict[str, List[str]]: A dictionary containing the cookie names as keys
64         and a list of values for each cookie.
65 
66     Example:
67         ```python
68         raw = 'name1=value1; name2="value2"; name3=value3'
69         cookies = parse_cookie(raw)
70         # cookies will be {'name1': ['value1'], 'name2': ['value2'], 'name3': ['value3']}
71         ```
72     """  # noqa: E501
73     cookies: Dict[str, List[str]] = {}
74 
75     for token in raw.split(";"):
76         name, __, value = token.partition("=")
77         name = name.strip()
78         value = value.strip()
79 
80         if not name:
81             continue
82 
83         if COOKIE_NAME_RESERVED_CHARS.search(name):  # no cov
84             continue
85 
86         if len(value) > 2 and value[0] == '"' and value[-1] == '"':  # no cov
87             value = _unquote(value)
88 
89         if name in cookies:
90             cookies[name].append(value)
91         else:
92             cookies[name] = [value]
93 
94     return cookies
95 
96 
97 class CookieRequestParameters(RequestParameters):
98     """A container for accessing single and multiple cookie values.
99 
100     Because the HTTP standard allows for multiple cookies with the same name,
101     a standard dictionary cannot be used to access cookie values. This class
102     provides a way to access cookie values in a way that is similar to a
103     dictionary, but also allows for accessing multiple values for a single
104     cookie name when necessary.
105 
106     Args:
107         cookies (Dict[str, List[str]]): A dictionary containing the cookie
108             names as keys and a list of values for each cookie.
109 
110     Example:
111         ```python
112         raw = 'name1=value1; name2="value2"; name3=value3'
113         cookies = parse_cookie(raw)
114         # cookies will be {'name1': ['value1'], 'name2': ['value2'], 'name3': ['value3']}
115 
116         request_cookies = CookieRequestParameters(cookies)
117         request_cookies['name1']  # 'value1'
118         request_cookies.get('name1')  # 'value1'
119         request_cookies.getlist('name1')  # ['value1']
120         ```
121     """  # noqa: E501
122 
123     def __getitem__(self, key: str) -> Optional[str]:
124         deprecation(
125             f"You are accessing cookie key '{key}', which is currently in "
126             "compat mode returning a single cookie value. Starting in v24.3 "
127             "accessing a cookie value like this will return a list of values. "
128             "To avoid this behavior and continue accessing a single value, "
129             f"please upgrade from request.cookies['{key}'] to "
130             f"request.cookies.get('{key}'). See more details: "
131             "https://sanic.dev/en/guide/release-notes/v23.3.html#request-cookies",  # noqa
132             24.3,
133         )
134         try:
135             value = self._get_prefixed_cookie(key)
136         except KeyError:
137             value = super().__getitem__(key)
138         return value[0]
139 
140     def __getattr__(self, key: str) -> str:
141         if key.startswith("_"):
142             return self.__getattribute__(key)
143         key = key.rstrip("_").replace("_", "-")
144         return str(self.get(key, ""))
145 
146     def get(self, name: str, default: Optional[Any] = None) -> Optional[Any]:
147         try:
148             return self._get_prefixed_cookie(name)[0]
149         except KeyError:
150             return super().get(name, default)
151 
152     def getlist(
153         self, name: str, default: Optional[Any] = None
154     ) -> Optional[Any]:
155         try:
156             return self._get_prefixed_cookie(name)
157         except KeyError:
158             return super().getlist(name, default)
159 
160     def _get_prefixed_cookie(self, name: str) -> Any:
161         getitem = super().__getitem__
162         try:
163             return getitem(f"{Cookie.HOST_PREFIX}{name}")
164         except KeyError:
165             return getitem(f"{Cookie.SECURE_PREFIX}{name}")
166
```
--- 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/sanic/cookies/request.py b/sanic/cookies/request.py
--- a/sanic/cookies/request.py
+++ b/sanic/cookies/request.py
@@ -73,12 +73,17 @@
     cookies: Dict[str, List[str]] = {}
 
     for token in raw.split(";"):
-        name, __, value = token.partition("=")
+        name, sep, value = token.partition("=")
         name = name.strip()
         value = value.strip()
 
-        if not name:
-            continue
+        # Support cookies =value or plain value with no name
+        # https://github.com/httpwg/http-extensions/issues/159
+        if not sep:
+            if not name:
+                # Empty value like ;; or a cookie header with no value
+                continue
+            name, value = "", name
 
         if COOKIE_NAME_RESERVED_CHARS.search(name):  # no cov
             continue
diff --git a/sanic/models/protocol_types.py b/sanic/models/protocol_types.py
--- a/sanic/models/protocol_types.py
+++ b/sanic/models/protocol_types.py
@@ -3,7 +3,7 @@
 import sys
 
 from asyncio import BaseTransport
-from typing import TYPE_CHECKING, Any, AnyStr, Optional
+from typing import TYPE_CHECKING, Any, Optional, Union
 
 
 if TYPE_CHECKING:
@@ -19,10 +19,10 @@
     from typing import Protocol
 
     class HTMLProtocol(Protocol):
-        def __html__(self) -> AnyStr:
+        def __html__(self) -> Union[str, bytes]:
             ...
 
-        def _repr_html_(self) -> AnyStr:
+        def _repr_html_(self) -> Union[str, bytes]:
             ...
 
     class Range(Protocol):

{"golden_diff": "diff --git a/sanic/cookies/request.py b/sanic/cookies/request.py\n--- a/sanic/cookies/request.py\n+++ b/sanic/cookies/request.py\n@@ -73,12 +73,17 @@\n     cookies: Dict[str, List[str]] = {}\n \n     for token in raw.split(\";\"):\n-        name, __, value = token.partition(\"=\")\n+        name, sep, value = token.partition(\"=\")\n         name = name.strip()\n         value = value.strip()\n \n-        if not name:\n-            continue\n+        # Support cookies =value or plain value with no name\n+        # https://github.com/httpwg/http-extensions/issues/159\n+        if not sep:\n+            if not name:\n+                # Empty value like ;; or a cookie header with no value\n+                continue\n+            name, value = \"\", name\n \n         if COOKIE_NAME_RESERVED_CHARS.search(name):  # no cov\n             continue\ndiff --git a/sanic/models/protocol_types.py b/sanic/models/protocol_types.py\n--- a/sanic/models/protocol_types.py\n+++ b/sanic/models/protocol_types.py\n@@ -3,7 +3,7 @@\n import sys\n \n from asyncio import BaseTransport\n-from typing import TYPE_CHECKING, Any, AnyStr, Optional\n+from typing import TYPE_CHECKING, Any, Optional, Union\n \n \n if TYPE_CHECKING:\n@@ -19,10 +19,10 @@\n     from typing import Protocol\n \n     class HTMLProtocol(Protocol):\n-        def __html__(self) -> AnyStr:\n+        def __html__(self) -> Union[str, bytes]:\n             ...\n \n-        def _repr_html_(self) -> AnyStr:\n+        def _repr_html_(self) -> Union[str, bytes]:\n             ...\n \n     class Range(Protocol):\n", "issue": "Cookie totally breaks if the client sets a bare cookie\n### Is there an existing issue for this?\r\n\r\n- [X] I have searched the existing issues\r\n\r\n### Describe the bug\r\n\r\nA cookie may be not in the `key=value` format. For example. if the JS code runs `document.cookie = \"bad\"`, it becomes:\r\n\r\n![image](https://github.com/sanic-org/sanic/assets/6646473/c9a1f53c-62bf-4516-9003-49fed08773dc)\r\n\r\nI don't know how to call it. I will use the term \"bare cookie\" in this report. In the following requests with a bare cookie, the Cookie HTTP header becomes: `Cookie: key=value; bad`\r\n\r\n![image](https://github.com/sanic-org/sanic/assets/6646473/536bdf38-61ad-4f31-bb78-6c7844433298)\r\n\r\nIt seems that Sanic cannot parse the header with bare cookies, and will throw all cookies (including the legimit `key=value` pair) away. See the code snippet below.\r\n\r\n### Code snippet\r\n\r\n```python\r\nfrom sanic import Sanic\r\nfrom sanic.response import html, text\r\n\r\napp = Sanic(\"test\")\r\napp.config.AUTO_EXTEND = False\r\n\r\n@app.get(\"/\")\r\nasync def route1(request):\r\n    return html('<script>document.cookie=\"key=value\"; document.cookie=\"bad\"; location.href=\"/fire\";</script>')\r\n    \r\n@app.get(\"/fire\")\r\nasync def route2(request):\r\n    return text(f'''\r\n        headers = {request.headers.get(\"Cookie\")}\r\n        key = {request.cookies.get(\"key\", \"none\")}\r\n    ''')\r\n\r\nif __name__ == '__main__':\r\n    app.run(port=4321, debug=True)\r\n```\r\n\r\nThen visit `http://127.0.0.1:4321/` in Chrome. The page shows:\r\n\r\n```\r\nheaders = key=value; bad\r\nkey = none\r\n```\r\n\r\n### Expected Behavior\r\n\r\nThe page should show:\r\n\r\n```\r\nheaders = key=value; bad\r\nkey = value\r\n```\r\n\r\n### How do you run Sanic?\r\n\r\nAs a script (`app.run` or `Sanic.serve`)\r\n\r\n### Operating System\r\n\r\nWindows\r\n\r\n### Sanic Version\r\n\r\n22.12.0\r\n\r\n### Additional context\r\n\r\nI am using the latest stable Chrome (117.0.5938.150) to reproduce this.\r\n\r\n\r\n\n", "before_files": [{"content": "from __future__ import annotations\n\nimport sys\n\nfrom asyncio import BaseTransport\nfrom typing import TYPE_CHECKING, Any, AnyStr, Optional\n\n\nif TYPE_CHECKING:\n    from sanic.http.constants import HTTP\n    from sanic.models.asgi import ASGIScope\n\n\nif sys.version_info < (3, 8):\n    Range = Any\n    HTMLProtocol = Any\nelse:\n    # Protocol is a 3.8+ feature\n    from typing import Protocol\n\n    class HTMLProtocol(Protocol):\n        def __html__(self) -> AnyStr:\n            ...\n\n        def _repr_html_(self) -> AnyStr:\n            ...\n\n    class Range(Protocol):\n        start: Optional[int]\n        end: Optional[int]\n        size: Optional[int]\n        total: Optional[int]\n        __slots__ = ()\n\n\nclass TransportProtocol(BaseTransport):\n    scope: ASGIScope\n    version: HTTP\n    __slots__ = ()\n", "path": "sanic/models/protocol_types.py"}, {"content": "import re\n\nfrom typing import Any, Dict, List, Optional\n\nfrom sanic.cookies.response import Cookie\nfrom sanic.log import deprecation\nfrom sanic.request.parameters import RequestParameters\n\n\nCOOKIE_NAME_RESERVED_CHARS = re.compile(\n    '[\\x00-\\x1F\\x7F-\\xFF()<>@,;:\\\\\\\\\"/[\\\\]?={} \\x09]'\n)\nOCTAL_PATTERN = re.compile(r\"\\\\[0-3][0-7][0-7]\")\nQUOTE_PATTERN = re.compile(r\"[\\\\].\")\n\n\ndef _unquote(str):  # no cov\n    if str is None or len(str) < 2:\n        return str\n    if str[0] != '\"' or str[-1] != '\"':\n        return str\n\n    str = str[1:-1]\n\n    i = 0\n    n = len(str)\n    res = []\n    while 0 <= i < n:\n        o_match = OCTAL_PATTERN.search(str, i)\n        q_match = QUOTE_PATTERN.search(str, i)\n        if not o_match and not q_match:\n            res.append(str[i:])\n            break\n        # else:\n        j = k = -1\n        if o_match:\n            j = o_match.start(0)\n        if q_match:\n            k = q_match.start(0)\n        if q_match and (not o_match or k < j):\n            res.append(str[i:k])\n            res.append(str[k + 1])\n            i = k + 2\n        else:\n            res.append(str[i:j])\n            res.append(chr(int(str[j + 1 : j + 4], 8)))  # noqa: E203\n            i = j + 4\n    return \"\".join(res)\n\n\ndef parse_cookie(raw: str) -> Dict[str, List[str]]:\n    \"\"\"Parses a raw cookie string into a dictionary.\n\n    The function takes a raw cookie string (usually from HTTP headers) and\n    returns a dictionary where each key is a cookie name and the value is a\n    list of values for that cookie. The function handles quoted values and\n    skips invalid cookie names.\n\n    Args:\n        raw (str): The raw cookie string to be parsed.\n\n    Returns:\n        Dict[str, List[str]]: A dictionary containing the cookie names as keys\n        and a list of values for each cookie.\n\n    Example:\n        ```python\n        raw = 'name1=value1; name2=\"value2\"; name3=value3'\n        cookies = parse_cookie(raw)\n        # cookies will be {'name1': ['value1'], 'name2': ['value2'], 'name3': ['value3']}\n        ```\n    \"\"\"  # noqa: E501\n    cookies: Dict[str, List[str]] = {}\n\n    for token in raw.split(\";\"):\n        name, __, value = token.partition(\"=\")\n        name = name.strip()\n        value = value.strip()\n\n        if not name:\n            continue\n\n        if COOKIE_NAME_RESERVED_CHARS.search(name):  # no cov\n            continue\n\n        if len(value) > 2 and value[0] == '\"' and value[-1] == '\"':  # no cov\n            value = _unquote(value)\n\n        if name in cookies:\n            cookies[name].append(value)\n        else:\n            cookies[name] = [value]\n\n    return cookies\n\n\nclass CookieRequestParameters(RequestParameters):\n    \"\"\"A container for accessing single and multiple cookie values.\n\n    Because the HTTP standard allows for multiple cookies with the same name,\n    a standard dictionary cannot be used to access cookie values. This class\n    provides a way to access cookie values in a way that is similar to a\n    dictionary, but also allows for accessing multiple values for a single\n    cookie name when necessary.\n\n    Args:\n        cookies (Dict[str, List[str]]): A dictionary containing the cookie\n            names as keys and a list of values for each cookie.\n\n    Example:\n        ```python\n        raw = 'name1=value1; name2=\"value2\"; name3=value3'\n        cookies = parse_cookie(raw)\n        # cookies will be {'name1': ['value1'], 'name2': ['value2'], 'name3': ['value3']}\n\n        request_cookies = CookieRequestParameters(cookies)\n        request_cookies['name1']  # 'value1'\n        request_cookies.get('name1')  # 'value1'\n        request_cookies.getlist('name1')  # ['value1']\n        ```\n    \"\"\"  # noqa: E501\n\n    def __getitem__(self, key: str) -> Optional[str]:\n        deprecation(\n            f\"You are accessing cookie key '{key}', which is currently in \"\n            \"compat mode returning a single cookie value. Starting in v24.3 \"\n            \"accessing a cookie value like this will return a list of values. \"\n            \"To avoid this behavior and continue accessing a single value, \"\n            f\"please upgrade from request.cookies['{key}'] to \"\n            f\"request.cookies.get('{key}'). See more details: \"\n            \"https://sanic.dev/en/guide/release-notes/v23.3.html#request-cookies\",  # noqa\n            24.3,\n        )\n        try:\n            value = self._get_prefixed_cookie(key)\n        except KeyError:\n            value = super().__getitem__(key)\n        return value[0]\n\n    def __getattr__(self, key: str) -> str:\n        if key.startswith(\"_\"):\n            return self.__getattribute__(key)\n        key = key.rstrip(\"_\").replace(\"_\", \"-\")\n        return str(self.get(key, \"\"))\n\n    def get(self, name: str, default: Optional[Any] = None) -> Optional[Any]:\n        try:\n            return self._get_prefixed_cookie(name)[0]\n        except KeyError:\n            return super().get(name, default)\n\n    def getlist(\n        self, name: str, default: Optional[Any] = None\n    ) -> Optional[Any]:\n        try:\n            return self._get_prefixed_cookie(name)\n        except KeyError:\n            return super().getlist(name, default)\n\n    def _get_prefixed_cookie(self, name: str) -> Any:\n        getitem = super().__getitem__\n        try:\n            return getitem(f\"{Cookie.HOST_PREFIX}{name}\")\n        except KeyError:\n            return getitem(f\"{Cookie.SECURE_PREFIX}{name}\")\n", "path": "sanic/cookies/request.py"}], "after_files": [{"content": "from __future__ import annotations\n\nimport sys\n\nfrom asyncio import BaseTransport\nfrom typing import TYPE_CHECKING, Any, Optional, Union\n\n\nif TYPE_CHECKING:\n    from sanic.http.constants import HTTP\n    from sanic.models.asgi import ASGIScope\n\n\nif sys.version_info < (3, 8):\n    Range = Any\n    HTMLProtocol = Any\nelse:\n    # Protocol is a 3.8+ feature\n    from typing import Protocol\n\n    class HTMLProtocol(Protocol):\n        def __html__(self) -> Union[str, bytes]:\n            ...\n\n        def _repr_html_(self) -> Union[str, bytes]:\n            ...\n\n    class Range(Protocol):\n        start: Optional[int]\n        end: Optional[int]\n        size: Optional[int]\n        total: Optional[int]\n        __slots__ = ()\n\n\nclass TransportProtocol(BaseTransport):\n    scope: ASGIScope\n    version: HTTP\n    __slots__ = ()\n", "path": "sanic/models/protocol_types.py"}, {"content": "import re\n\nfrom typing import Any, Dict, List, Optional\n\nfrom sanic.cookies.response import Cookie\nfrom sanic.log import deprecation\nfrom sanic.request.parameters import RequestParameters\n\n\nCOOKIE_NAME_RESERVED_CHARS = re.compile(\n    '[\\x00-\\x1F\\x7F-\\xFF()<>@,;:\\\\\\\\\"/[\\\\]?={} \\x09]'\n)\nOCTAL_PATTERN = re.compile(r\"\\\\[0-3][0-7][0-7]\")\nQUOTE_PATTERN = re.compile(r\"[\\\\].\")\n\n\ndef _unquote(str):  # no cov\n    if str is None or len(str) < 2:\n        return str\n    if str[0] != '\"' or str[-1] != '\"':\n        return str\n\n    str = str[1:-1]\n\n    i = 0\n    n = len(str)\n    res = []\n    while 0 <= i < n:\n        o_match = OCTAL_PATTERN.search(str, i)\n        q_match = QUOTE_PATTERN.search(str, i)\n        if not o_match and not q_match:\n            res.append(str[i:])\n            break\n        # else:\n        j = k = -1\n        if o_match:\n            j = o_match.start(0)\n        if q_match:\n            k = q_match.start(0)\n        if q_match and (not o_match or k < j):\n            res.append(str[i:k])\n            res.append(str[k + 1])\n            i = k + 2\n        else:\n            res.append(str[i:j])\n            res.append(chr(int(str[j + 1 : j + 4], 8)))  # noqa: E203\n            i = j + 4\n    return \"\".join(res)\n\n\ndef parse_cookie(raw: str) -> Dict[str, List[str]]:\n    \"\"\"Parses a raw cookie string into a dictionary.\n\n    The function takes a raw cookie string (usually from HTTP headers) and\n    returns a dictionary where each key is a cookie name and the value is a\n    list of values for that cookie. The function handles quoted values and\n    skips invalid cookie names.\n\n    Args:\n        raw (str): The raw cookie string to be parsed.\n\n    Returns:\n        Dict[str, List[str]]: A dictionary containing the cookie names as keys\n        and a list of values for each cookie.\n\n    Example:\n        ```python\n        raw = 'name1=value1; name2=\"value2\"; name3=value3'\n        cookies = parse_cookie(raw)\n        # cookies will be {'name1': ['value1'], 'name2': ['value2'], 'name3': ['value3']}\n        ```\n    \"\"\"  # noqa: E501\n    cookies: Dict[str, List[str]] = {}\n\n    for token in raw.split(\";\"):\n        name, sep, value = token.partition(\"=\")\n        name = name.strip()\n        value = value.strip()\n\n        # Support cookies =value or plain value with no name\n        # https://github.com/httpwg/http-extensions/issues/159\n        if not sep:\n            if not name:\n                # Empty value like ;; or a cookie header with no value\n                continue\n            name, value = \"\", name\n\n        if COOKIE_NAME_RESERVED_CHARS.search(name):  # no cov\n            continue\n\n        if len(value) > 2 and value[0] == '\"' and value[-1] == '\"':  # no cov\n            value = _unquote(value)\n\n        if name in cookies:\n            cookies[name].append(value)\n        else:\n            cookies[name] = [value]\n\n    return cookies\n\n\nclass CookieRequestParameters(RequestParameters):\n    \"\"\"A container for accessing single and multiple cookie values.\n\n    Because the HTTP standard allows for multiple cookies with the same name,\n    a standard dictionary cannot be used to access cookie values. This class\n    provides a way to access cookie values in a way that is similar to a\n    dictionary, but also allows for accessing multiple values for a single\n    cookie name when necessary.\n\n    Args:\n        cookies (Dict[str, List[str]]): A dictionary containing the cookie\n            names as keys and a list of values for each cookie.\n\n    Example:\n        ```python\n        raw = 'name1=value1; name2=\"value2\"; name3=value3'\n        cookies = parse_cookie(raw)\n        # cookies will be {'name1': ['value1'], 'name2': ['value2'], 'name3': ['value3']}\n\n        request_cookies = CookieRequestParameters(cookies)\n        request_cookies['name1']  # 'value1'\n        request_cookies.get('name1')  # 'value1'\n        request_cookies.getlist('name1')  # ['value1']\n        ```\n    \"\"\"  # noqa: E501\n\n    def __getitem__(self, key: str) -> Optional[str]:\n        deprecation(\n            f\"You are accessing cookie key '{key}', which is currently in \"\n            \"compat mode returning a single cookie value. Starting in v24.3 \"\n            \"accessing a cookie value like this will return a list of values. \"\n            \"To avoid this behavior and continue accessing a single value, \"\n            f\"please upgrade from request.cookies['{key}'] to \"\n            f\"request.cookies.get('{key}'). See more details: \"\n            \"https://sanic.dev/en/guide/release-notes/v23.3.html#request-cookies\",  # noqa\n            24.3,\n        )\n        try:\n            value = self._get_prefixed_cookie(key)\n        except KeyError:\n            value = super().__getitem__(key)\n        return value[0]\n\n    def __getattr__(self, key: str) -> str:\n        if key.startswith(\"_\"):\n            return self.__getattribute__(key)\n        key = key.rstrip(\"_\").replace(\"_\", \"-\")\n        return str(self.get(key, \"\"))\n\n    def get(self, name: str, default: Optional[Any] = None) -> Optional[Any]:\n        try:\n            return self._get_prefixed_cookie(name)[0]\n        except KeyError:\n            return super().get(name, default)\n\n    def getlist(\n        self, name: str, default: Optional[Any] = None\n    ) -> Optional[Any]:\n        try:\n            return self._get_prefixed_cookie(name)\n        except KeyError:\n            return super().getlist(name, default)\n\n    def _get_prefixed_cookie(self, name: str) -> Any:\n        getitem = super().__getitem__\n        try:\n            return getitem(f\"{Cookie.HOST_PREFIX}{name}\")\n        except KeyError:\n            return getitem(f\"{Cookie.SECURE_PREFIX}{name}\")\n", "path": "sanic/cookies/request.py"}]}