Compare commits

..

2 Commits

Author SHA1 Message Date
L. Kärkkäinen
a202435283 Skip empty cookie records. Add tests. 2023-10-14 20:03:43 +01:00
L. Kärkkäinen
6d433af406 Accept bare cookies 2023-10-14 18:27:26 +00:00
5 changed files with 21 additions and 93 deletions

View File

@@ -1369,12 +1369,6 @@ class Sanic(
protocol = request.transport.get_protocol() protocol = request.transport.get_protocol()
ws = await protocol.websocket_handshake(request, subprotocols) ws = await protocol.websocket_handshake(request, subprotocols)
await self.dispatch(
"websocket.handler.before",
inline=True,
context={"request": request, "websocket": ws},
fail_not_found=False,
)
# schedule the application handler # schedule the application handler
# its future is kept in self.websocket_tasks in case it # its future is kept in self.websocket_tasks in case it
# needs to be cancelled due to the server being stopped # needs to be cancelled due to the server being stopped
@@ -1383,24 +1377,10 @@ class Sanic(
cancelled = False cancelled = False
try: try:
await fut await fut
await self.dispatch(
"websocket.handler.after",
inline=True,
context={"request": request, "websocket": ws},
reverse=True,
fail_not_found=False,
)
except (CancelledError, ConnectionClosed): # type: ignore except (CancelledError, ConnectionClosed): # type: ignore
cancelled = True cancelled = True
except Exception as e: except Exception as e:
self.error_handler.log(request, e) self.error_handler.log(request, e)
await self.dispatch(
"websocket.handler.exception",
inline=True,
context={"request": request, "websocket": ws, "exception": e},
reverse=True,
fail_not_found=False,
)
finally: finally:
self.websocket_tasks.remove(fut) self.websocket_tasks.remove(fut)
if cancelled: if cancelled:

View File

@@ -73,12 +73,16 @@ def parse_cookie(raw: str) -> Dict[str, List[str]]:
cookies: Dict[str, List[str]] = {} cookies: Dict[str, List[str]] = {}
for token in raw.split(";"): for token in raw.split(";"):
name, __, value = token.partition("=") name, sep, value = token.partition("=")
name = name.strip() name = name.strip()
value = value.strip() value = value.strip()
# Support cookies =value or plain value with no name
# https://github.com/httpwg/http-extensions/issues/159
if not sep:
if not name: if not name:
continue continue # Empty value like ;; or a cookie header with no value
name, value = "", name
if COOKIE_NAME_RESERVED_CHARS.search(name): # no cov if COOKIE_NAME_RESERVED_CHARS.search(name): # no cov
continue continue

View File

@@ -38,9 +38,6 @@ class Event(Enum):
HTTP_LIFECYCLE_SEND = "http.lifecycle.send" HTTP_LIFECYCLE_SEND = "http.lifecycle.send"
HTTP_MIDDLEWARE_AFTER = "http.middleware.after" HTTP_MIDDLEWARE_AFTER = "http.middleware.after"
HTTP_MIDDLEWARE_BEFORE = "http.middleware.before" HTTP_MIDDLEWARE_BEFORE = "http.middleware.before"
WEBSOCKET_HANDLER_AFTER = "websocket.handler.after"
WEBSOCKET_HANDLER_BEFORE = "websocket.handler.before"
WEBSOCKET_HANDLER_EXCEPTION = "websocket.handler.exception"
RESERVED_NAMESPACES = { RESERVED_NAMESPACES = {
@@ -68,11 +65,6 @@ RESERVED_NAMESPACES = {
Event.HTTP_MIDDLEWARE_AFTER.value, Event.HTTP_MIDDLEWARE_AFTER.value,
Event.HTTP_MIDDLEWARE_BEFORE.value, Event.HTTP_MIDDLEWARE_BEFORE.value,
), ),
"websocket": {
Event.WEBSOCKET_HANDLER_AFTER.value,
Event.WEBSOCKET_HANDLER_BEFORE.value,
Event.WEBSOCKET_HANDLER_EXCEPTION.value,
},
} }

View File

@@ -11,6 +11,20 @@ from sanic.cookies.request import CookieRequestParameters
from sanic.exceptions import ServerError from sanic.exceptions import ServerError
from sanic.response import text from sanic.response import text
from sanic.response.convenience import json from sanic.response.convenience import json
from sanic.cookies.request import parse_cookie
def test_request_cookies():
cdict = parse_cookie("foo=one; foo=two; abc = xyz;;bare;=bare2")
assert cdict == {
"foo": ["one", "two"],
"abc": ["xyz"],
"": ["bare", "bare2"],
}
c = CookieRequestParameters(cdict)
assert c.getlist("foo") == ["one", "two"]
assert c.getlist("abc") == ["xyz"]
assert c.getlist("") == ["bare", "bare2"]
assert c.getlist("bare") == None # [] might be sensible but we got None for now
# ------------------------------------------------------------ # # ------------------------------------------------------------ #

View File

@@ -54,65 +54,3 @@ def test_ws_handler_async_for(
) )
assert ws_proxy.client_sent == ["test 1", "test 2", ""] assert ws_proxy.client_sent == ["test 1", "test 2", ""]
assert ws_proxy.client_received == ["test 1", "test 2"] assert ws_proxy.client_received == ["test 1", "test 2"]
def signalapp(app):
@app.signal("websocket.handler.before")
async def ws_before(request: Request, websocket: Websocket):
app.ctx.seq.append("before")
print("before")
await websocket.send("before: " + await websocket.recv())
print("before2")
@app.signal("websocket.handler.after")
async def ws_after(request: Request, websocket: Websocket):
app.ctx.seq.append("after")
await websocket.send("after: " + await websocket.recv())
await websocket.recv()
@app.signal("websocket.handler.exception")
async def ws_exception(
request: Request, websocket: Websocket, exception: Exception
):
app.ctx.seq.append("exception")
await websocket.send(f"exception: {exception}")
await websocket.recv()
@app.websocket("/ws")
async def ws_handler(request: Request, ws: Websocket):
app.ctx.seq.append("ws")
@app.websocket("/wserror")
async def ws_error(request: Request, ws: Websocket):
print("wserr")
app.ctx.seq.append("wserror")
raise Exception(await ws.recv())
print("wserr2")
def test_ws_signals(
app: Sanic,
simple_ws_mimic_client: MimicClientType,
):
signalapp(app)
app.ctx.seq = []
_, ws_proxy = app.test_client.websocket(
"/ws", mimic=simple_ws_mimic_client
)
assert ws_proxy.client_received == ["before: test 1", "after: test 2"]
assert app.ctx.seq == ["before", "ws", "after"]
def test_ws_signals_exception(
app: Sanic,
simple_ws_mimic_client: MimicClientType,
):
signalapp(app)
app.ctx.seq = []
_, ws_proxy = app.test_client.websocket(
"/wserror", mimic=simple_ws_mimic_client
)
assert ws_proxy.client_received == ["before: test 1", "exception: test 2"]
assert app.ctx.seq == ["before", "wserror", "exception"]