-
-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Description
Long story short
aiohttp servers fail with 500 Internal error on requests where Cookie header is present and cookie name contains invalid symbols for cookie name. aiohttp uses SimpleCookie from python's http.cookies package. Although SimpleCookie follows standards and supposedly correctly rejects such cookie names, real world is much messier and such cookies are seen frequently.
For the reference, RFC2109 states that cookie attribute (name) is a token
:
The two state management headers, Set-Cookie and Cookie, have common
syntactic properties involving attribute-value pairs. The following
grammar uses the notation, and tokens DIGIT (decimal digits) and
token (informally, a sequence of non-special, non-white space
characters) from the HTTP/1.1 specification [RFC 2068] to describe
their syntax.
av-pairs = av-pair *(";" av-pair)
av-pair = attr ["=" value] ; optional value
attr = token
RFC2616 defines token
as:
token = 1*<any CHAR except CTLs or separators>
separators = "(" | ")" | "<" | ">" | "@"
| "," | ";" | ":" | "\" | <">
| "/" | "[" | "]" | "?" | "="
| "{" | "}" | SP | HT
So any cookie attribute containing one of ( ) < > @ , ; : \ " / [ ] ? = { } SP HT
is considered invalid by SimpleCookie. Django uses own cookie parsing because of similar reasons.
Expected behaviour
Such invalid cookie should still be accepted as they are tolerated by browsers and most web servers.
Actual behaviour
500 Internal server error caused by exception CookieError.
Steps to reproduce
Given sample http server:
from aiohttp import web
async def handle(request):
text = ""
for k, v in request.cookies:
text += '\n{}\t{}'.format(k, v)
return web.Response(text=text)
app = web.Application()
app.router.add_get('/', handle)
app.router.add_get('/{name}', handle)
web.run_app(app)
When one executes curl -H 'Cookie: ISAWPLB{DB45DF86-F806-407C-932C-D52A60E4019E}=x' -v http://localhost:8080/
against this server it receives 500 internal server error. On the server side a traceback is visible:
Error handling request
Traceback (most recent call last):
File "/usr/local/lib/python3.5/dist-packages/aiohttp/helpers.py", line 554, in __get__
return inst._cache[self.name]
KeyError: 'cookies'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/usr/local/lib/python3.5/dist-packages/aiohttp/web_protocol.py", line 410, in start
resp = yield from self._request_handler(request)
File "/usr/local/lib/python3.5/dist-packages/aiohttp/web.py", line 325, in _handle
resp = yield from handler(request)
File "/usr/local/lib/python3.5/dist-packages/aiohttp/web_middlewares.py", line 93, in impl
return (yield from handler(request))
File "./test.py", line 7, in handle
for k, v in request.cookies:
File "/usr/local/lib/python3.5/dist-packages/aiohttp/helpers.py", line 556, in __get__
val = self.wrapped(inst)
File "/usr/local/lib/python3.5/dist-packages/aiohttp/web_request.py", line 413, in cookies
parsed = SimpleCookie(raw)
File "/usr/lib/python3.5/http/cookies.py", line 507, in __init__
self.load(input)
File "/usr/lib/python3.5/http/cookies.py", line 556, in load
self.__parse_string(rawdata)
File "/usr/lib/python3.5/http/cookies.py", line 620, in __parse_string
self.__set(key, rval, cval)
File "/usr/lib/python3.5/http/cookies.py", line 512, in __set
M.set(key, real_value, coded_value)
File "/usr/lib/python3.5/http/cookies.py", line 380, in set
raise CookieError('Illegal key %r' % (key,))
http.cookies.CookieError: Illegal key 'ISAWPLB{DB45DF86-F806-407C-932C-D52A60E4019E}'
Your environment
Tested on Ubuntu 16.04, aiohttp version 2.3.9 installed through pip.