forked from aiortc/aioquic
-
Notifications
You must be signed in to change notification settings - Fork 0
/
demo.py
146 lines (124 loc) · 4.06 KB
/
demo.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#
# demo application for http3_server.py
#
import datetime
import os
from urllib.parse import urlencode
from starlette.applications import Starlette
from starlette.responses import PlainTextResponse, Response
from starlette.routing import Mount, Route, WebSocketRoute
from starlette.staticfiles import StaticFiles
from starlette.templating import Jinja2Templates
from starlette.types import Receive, Scope, Send
from starlette.websockets import WebSocketDisconnect
ROOT = os.path.dirname(__file__)
STATIC_ROOT = os.environ.get("STATIC_ROOT", os.path.join(ROOT, "htdocs"))
STATIC_URL = "/"
LOGS_PATH = os.path.join(STATIC_ROOT, "logs")
QVIS_URL = "https://qvis.quictools.info/"
templates = Jinja2Templates(directory=os.path.join(ROOT, "templates"))
async def homepage(request):
"""
Simple homepage.
"""
await request.send_push_promise("/style.css")
return templates.TemplateResponse("index.html", {"request": request})
async def echo(request):
"""
HTTP echo endpoint.
"""
content = await request.body()
media_type = request.headers.get("content-type")
return Response(content, media_type=media_type)
async def logs(request):
"""
Browsable list of QLOG files.
"""
logs = []
for name in os.listdir(LOGS_PATH):
if name.endswith(".qlog"):
s = os.stat(os.path.join(LOGS_PATH, name))
file_url = "https://" + request.headers["host"] + "/logs/" + name
logs.append(
{
"date": datetime.datetime.utcfromtimestamp(s.st_mtime).strftime(
"%Y-%m-%d %H:%M:%S"
),
"file_url": file_url,
"name": name[:-5],
"qvis_url": QVIS_URL
+ "?"
+ urlencode({"file": file_url})
+ "#/sequence",
"size": s.st_size,
}
)
return templates.TemplateResponse(
"logs.html",
{
"logs": sorted(logs, key=lambda x: x["date"], reverse=True),
"request": request,
},
)
async def padding(request):
"""
Dynamically generated data, maximum 50MB.
"""
size = min(50000000, request.path_params["size"])
return PlainTextResponse("Z" * size)
async def ws(websocket):
"""
WebSocket echo endpoint.
"""
if "chat" in websocket.scope["subprotocols"]:
subprotocol = "chat"
else:
subprotocol = None
await websocket.accept(subprotocol=subprotocol)
try:
while True:
message = await websocket.receive_text()
await websocket.send_text(message)
except WebSocketDisconnect:
pass
async def wt(scope: Scope, receive: Receive, send: Send) -> None:
"""
WebTransport echo endpoint.
"""
# accept connection
message = await receive()
assert message["type"] == "webtransport.connect"
await send({"type": "webtransport.accept"})
# echo back received data
while True:
message = await receive()
if message["type"] == "webtransport.datagram.receive":
await send(
{
"data": message["data"],
"type": "webtransport.datagram.send",
}
)
elif message["type"] == "webtransport.stream.receive":
await send(
{
"data": message["data"],
"stream": message["stream"],
"type": "webtransport.stream.send",
}
)
starlette = Starlette(
routes=[
Route("/", homepage),
Route("/{size:int}", padding),
Route("/echo", echo, methods=["POST"]),
Route("/logs", logs),
WebSocketRoute("/ws", ws),
Mount(STATIC_URL, StaticFiles(directory=STATIC_ROOT, html=True)),
]
)
async def app(scope: Scope, receive: Receive, send: Send) -> None:
if scope["type"] == "webtransport" and scope["path"] == "/wt":
await wt(scope, receive, send)
else:
await starlette(scope, receive, send)