|
87 | 87 | such trickeries do not confuse it. |
88 | 88 |
|
89 | 89 | >>> C = cookies.SimpleCookie() |
90 | | - >>> C.load('keebler="E=everybody; L=\\"Loves\\"; fudge=\\012;";') |
| 90 | + >>> C.load('keebler="E=everybody; L=\\"Loves\\"; fudge=;";') |
91 | 91 | >>> print(C) |
92 | | - Set-Cookie: keebler="E=everybody; L=\"Loves\"; fudge=\012;" |
| 92 | + Set-Cookie: keebler="E=everybody; L=\"Loves\"; fudge=;" |
93 | 93 |
|
94 | 94 | Each element of the Cookie also supports all of the RFC 2109 |
95 | 95 | Cookie attributes. Here's an example which sets the Path |
@@ -170,6 +170,15 @@ class CookieError(Exception): |
170 | 170 | }) |
171 | 171 |
|
172 | 172 | _is_legal_key = re.compile('[%s]+' % re.escape(_LegalChars)).fullmatch |
| 173 | +_control_character_re = re.compile(r'[\x00-\x1F\x7F]') |
| 174 | + |
| 175 | + |
| 176 | +def _has_control_character(*val): |
| 177 | + """Detects control characters within a value. |
| 178 | + Supports any type, as header values can be any type. |
| 179 | + """ |
| 180 | + return any(_control_character_re.search(str(v)) for v in val) |
| 181 | + |
173 | 182 |
|
174 | 183 | def _quote(str): |
175 | 184 | r"""Quote a string for use in a cookie header. |
@@ -292,12 +301,16 @@ def __setitem__(self, K, V): |
292 | 301 | K = K.lower() |
293 | 302 | if not K in self._reserved: |
294 | 303 | raise CookieError("Invalid attribute %r" % (K,)) |
| 304 | + if _has_control_character(K, V): |
| 305 | + raise CookieError(f"Control characters are not allowed in cookies {K!r} {V!r}") |
295 | 306 | dict.__setitem__(self, K, V) |
296 | 307 |
|
297 | 308 | def setdefault(self, key, val=None): |
298 | 309 | key = key.lower() |
299 | 310 | if key not in self._reserved: |
300 | 311 | raise CookieError("Invalid attribute %r" % (key,)) |
| 312 | + if _has_control_character(key, val): |
| 313 | + raise CookieError("Control characters are not allowed in cookies %r %r" % (key, val,)) |
301 | 314 | return dict.setdefault(self, key, val) |
302 | 315 |
|
303 | 316 | def __eq__(self, morsel): |
@@ -333,6 +346,9 @@ def set(self, key, val, coded_val): |
333 | 346 | raise CookieError('Attempt to set a reserved key %r' % (key,)) |
334 | 347 | if not _is_legal_key(key): |
335 | 348 | raise CookieError('Illegal key %r' % (key,)) |
| 349 | + if _has_control_character(key, val, coded_val): |
| 350 | + raise CookieError( |
| 351 | + "Control characters are not allowed in cookies %r %r %r" % (key, val, coded_val,)) |
336 | 352 |
|
337 | 353 | # It's a good key, so save it. |
338 | 354 | self._key = key |
@@ -484,7 +500,10 @@ def output(self, attrs=None, header="Set-Cookie:", sep="\015\012"): |
484 | 500 | result = [] |
485 | 501 | items = sorted(self.items()) |
486 | 502 | for key, value in items: |
487 | | - result.append(value.output(attrs, header)) |
| 503 | + value_output = value.output(attrs, header) |
| 504 | + if _has_control_character(value_output): |
| 505 | + raise CookieError("Control characters are not allowed in cookies") |
| 506 | + result.append(value_output) |
488 | 507 | return sep.join(result) |
489 | 508 |
|
490 | 509 | __str__ = output |
|
0 commit comments