HTTP/3 Support (#2378)
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
from .altsvc import AltSvcCheck # noqa
|
||||
from .base import BaseScheme
|
||||
from .ode import OptionalDispatchEvent # noqa
|
||||
|
||||
|
||||
56
sanic/touchup/schemes/altsvc.py
Normal file
56
sanic/touchup/schemes/altsvc.py
Normal file
@@ -0,0 +1,56 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from ast import Assign, Constant, NodeTransformer, Subscript
|
||||
from typing import TYPE_CHECKING, Any, List
|
||||
|
||||
from sanic.http.constants import HTTP
|
||||
|
||||
from .base import BaseScheme
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from sanic import Sanic
|
||||
|
||||
|
||||
class AltSvcCheck(BaseScheme):
|
||||
ident = "ALTSVC"
|
||||
|
||||
def visitors(self) -> List[NodeTransformer]:
|
||||
return [RemoveAltSvc(self.app, self.app.state.verbosity)]
|
||||
|
||||
|
||||
class RemoveAltSvc(NodeTransformer):
|
||||
def __init__(self, app: Sanic, verbosity: int = 0) -> None:
|
||||
self._app = app
|
||||
self._verbosity = verbosity
|
||||
self._versions = {
|
||||
info.settings["version"] for info in app.state.server_info
|
||||
}
|
||||
|
||||
def visit_Assign(self, node: Assign) -> Any:
|
||||
if any(self._matches(target) for target in node.targets):
|
||||
if self._should_remove():
|
||||
return None
|
||||
assert isinstance(node.value, Constant)
|
||||
node.value.value = self.value()
|
||||
return node
|
||||
|
||||
def _should_remove(self) -> bool:
|
||||
return len(self._versions) == 1
|
||||
|
||||
@staticmethod
|
||||
def _matches(node) -> bool:
|
||||
return (
|
||||
isinstance(node, Subscript)
|
||||
and isinstance(node.slice, Constant)
|
||||
and node.slice.value == "alt-svc"
|
||||
)
|
||||
|
||||
def value(self):
|
||||
values = []
|
||||
for info in self._app.state.server_info:
|
||||
port = info.settings["port"]
|
||||
version = info.settings["version"]
|
||||
if version is HTTP.VERSION_3:
|
||||
values.append(f'h3=":{port}"')
|
||||
return ", ".join(values)
|
||||
@@ -1,5 +1,8 @@
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import Set, Type
|
||||
from ast import NodeTransformer, parse
|
||||
from inspect import getsource
|
||||
from textwrap import dedent
|
||||
from typing import Any, Dict, List, Set, Type
|
||||
|
||||
|
||||
class BaseScheme(ABC):
|
||||
@@ -10,11 +13,26 @@ class BaseScheme(ABC):
|
||||
self.app = app
|
||||
|
||||
@abstractmethod
|
||||
def run(self, method, module_globals) -> None:
|
||||
def visitors(self) -> List[NodeTransformer]:
|
||||
...
|
||||
|
||||
def __init_subclass__(cls):
|
||||
BaseScheme._registry.add(cls)
|
||||
|
||||
def __call__(self, method, module_globals):
|
||||
return self.run(method, module_globals)
|
||||
def __call__(self):
|
||||
return self.visitors()
|
||||
|
||||
@classmethod
|
||||
def build(cls, method, module_globals, app):
|
||||
raw_source = getsource(method)
|
||||
src = dedent(raw_source)
|
||||
node = parse(src)
|
||||
|
||||
for scheme in cls._registry:
|
||||
for visitor in scheme(app)():
|
||||
node = visitor.visit(node)
|
||||
|
||||
compiled_src = compile(node, method.__name__, "exec")
|
||||
exec_locals: Dict[str, Any] = {}
|
||||
exec(compiled_src, module_globals, exec_locals) # nosec
|
||||
return exec_locals[method.__name__]
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
from ast import Attribute, Await, Dict, Expr, NodeTransformer, parse
|
||||
from inspect import getsource
|
||||
from textwrap import dedent
|
||||
from typing import Any
|
||||
from ast import Attribute, Await, Expr, NodeTransformer
|
||||
from typing import Any, List
|
||||
|
||||
from sanic.log import logger
|
||||
|
||||
@@ -20,16 +18,8 @@ class OptionalDispatchEvent(BaseScheme):
|
||||
signal.name for signal in app.signal_router.routes
|
||||
]
|
||||
|
||||
def run(self, method, module_globals):
|
||||
raw_source = getsource(method)
|
||||
src = dedent(raw_source)
|
||||
tree = parse(src)
|
||||
node = RemoveDispatch(self._registered_events).visit(tree)
|
||||
compiled_src = compile(node, method.__name__, "exec")
|
||||
exec_locals: Dict[str, Any] = {}
|
||||
exec(compiled_src, module_globals, exec_locals) # nosec
|
||||
|
||||
return exec_locals[method.__name__]
|
||||
def visitors(self) -> List[NodeTransformer]:
|
||||
return [RemoveDispatch(self._registered_events)]
|
||||
|
||||
def _sync_events(self):
|
||||
all_events = set()
|
||||
|
||||
@@ -21,10 +21,8 @@ class TouchUp:
|
||||
|
||||
module = getmodule(target)
|
||||
module_globals = dict(getmembers(module))
|
||||
|
||||
for scheme in BaseScheme._registry:
|
||||
modified = scheme(app)(method, module_globals)
|
||||
setattr(target, method_name, modified)
|
||||
modified = BaseScheme.build(method, module_globals, app)
|
||||
setattr(target, method_name, modified)
|
||||
|
||||
target.__touched__ = True
|
||||
|
||||
|
||||
Reference in New Issue
Block a user