-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
QUIC: protocol: inhouse implementation of quic and h3 client server p…
…air using aioquic APIs
- Loading branch information
Showing
14 changed files
with
1,622 additions
and
37 deletions.
There are no files selected for viewing
Submodule aioquic
updated
28 files
+1 −1 | README.rst | |
+2 −6 | examples/doq_server.py | |
+3 −5 | examples/http3_server.py | |
+93 −46 | examples/interop.py | |
+1 −1 | src/aioquic/about.py | |
+7 −7 | src/aioquic/asyncio/server.py | |
+8 −3 | src/aioquic/h0/connection.py | |
+1 −1 | src/aioquic/h3/connection.py | |
+6 −1 | src/aioquic/quic/configuration.py | |
+306 −98 | src/aioquic/quic/connection.py | |
+49 −14 | src/aioquic/quic/crypto.py | |
+13 −10 | src/aioquic/quic/logger.py | |
+20 −7 | src/aioquic/quic/packet.py | |
+24 −30 | src/aioquic/quic/packet_builder.py | |
+26 −22 | src/aioquic/quic/recovery.py | |
+24 −6 | src/aioquic/quic/stream.py | |
+8 −4 | src/aioquic/tls.py | |
+ − | tests/retry_draft_28.bin | |
+ − | tests/retry_draft_29.bin | |
+7 −11 | tests/test_asyncio.py | |
+370 −65 | tests/test_connection.py | |
+46 −46 | tests/test_crypto.py | |
+319 −0 | tests/test_crypto_draft_28.py | |
+42 −0 | tests/test_h0.py | |
+51 −3 | tests/test_packet.py | |
+64 −0 | tests/test_packet_builder.py | |
+3 −1 | tests/test_recovery.py | |
+49 −5 | tests/test_stream.py |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
# | ||
# demo application for http3_server.py | ||
# | ||
|
||
import datetime | ||
import os | ||
from urllib.parse import urlencode | ||
|
||
import httpbin | ||
from asgiref.wsgi import WsgiToAsgi | ||
from starlette.applications import Starlette | ||
from starlette.responses import PlainTextResponse, Response | ||
from starlette.staticfiles import StaticFiles | ||
from starlette.templating import Jinja2Templates | ||
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.edm.uhasselt.be/" | ||
|
||
templates = Jinja2Templates(directory=os.path.join(ROOT, "templates")) | ||
app = Starlette() | ||
|
||
|
||
@app.route("/") | ||
async def homepage(request): | ||
""" | ||
Simple homepage. | ||
""" | ||
await request.send_push_promise("/style.css") | ||
return templates.TemplateResponse("index.html", {"request": request}) | ||
|
||
|
||
@app.route("/echo", methods=["POST"]) | ||
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) | ||
|
||
|
||
@app.route("/logs/?") | ||
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, | ||
}, | ||
) | ||
|
||
|
||
@app.route("/{size:int}") | ||
def padding(request): | ||
""" | ||
Dynamically generated data, maximum 50MB. | ||
""" | ||
size = min(50000000, request.path_params["size"]) | ||
return PlainTextResponse("Z" * size) | ||
|
||
|
||
@app.websocket_route("/ws") | ||
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 | ||
|
||
|
||
app.mount("/httpbin", WsgiToAsgi(httpbin.app)) | ||
|
||
app.mount(STATIC_URL, StaticFiles(directory=STATIC_ROOT, html=True)) |
Oops, something went wrong.