1515from traitlets .config import Configurable
1616
1717from .handlers import AddSlashHandler , NamedLocalProxyHandler , SuperviseAndProxyHandler
18+ from .websockify import WebsockifyHandler , SuperviseAndWebsockifyHandler
1819
1920try :
2021 # Traitlets >= 4.3.3
4142 "new_browser_tab" ,
4243 "request_headers_override" ,
4344 "rewrite_response" ,
45+ "websockify" ,
4446 ],
4547)
4648
4749
48- def _make_namedproxy_handler (sp : ServerProcess ):
49- class _Proxy (NamedLocalProxyHandler ):
50- def __init__ (self , * args , ** kwargs ):
51- super ().__init__ (* args , ** kwargs )
52- self .name = sp .name
53- self .proxy_base = sp .name
54- self .absolute_url = sp .absolute_url
55- self .port = sp .port
56- self .unix_socket = sp .unix_socket
57- self .mappath = sp .mappath
58- self .rewrite_response = sp .rewrite_response
59-
60- def get_request_headers_override (self ):
61- return self ._realize_rendered_template (sp .request_headers_override )
62-
63- return _Proxy
64-
65-
66- def _make_supervisedproxy_handler (sp : ServerProcess ):
50+ def _make_proxy_handler (sp : ServerProcess ):
6751 """
68- Create a SuperviseAndProxyHandler subclass with given parameters
52+ Create an appropriate handler with given parameters
6953 """
54+ if sp .command :
55+ cls = SuperviseAndWebsockifyHandler if sp .websockify else SuperviseAndProxyHandler
56+ args = dict (state = {})
57+ elif not (sp .port or isinstance (sp .unix_socket , str )):
58+ warn (
59+ f"Server proxy { sp .name } does not have a command, port "
60+ f"number or unix_socket path. At least one of these is "
61+ f"required."
62+ )
63+ return
64+ else :
65+ cls = WebsockifyHandler if sp .websockify else NamedLocalProxyHandler
66+ args = {}
7067
7168 # FIXME: Set 'name' properly
72- class _Proxy (SuperviseAndProxyHandler ):
69+ class _Proxy (cls ):
70+ kwargs = args
71+
7372 def __init__ (self , * args , ** kwargs ):
7473 super ().__init__ (* args , ** kwargs )
7574 self .name = sp .name
7675 self .command = sp .command
7776 self .proxy_base = sp .name
7877 self .absolute_url = sp .absolute_url
79- self .requested_port = sp .port
80- self .requested_unix_socket = sp .unix_socket
78+ if sp .command :
79+ self .requested_port = sp .port
80+ self .requested_unix_socket = sp .unix_socket
81+ else :
82+ self .port = sp .port
83+ self .unix_socket = sp .unix_socket
8184 self .mappath = sp .mappath
8285 self .rewrite_response = sp .rewrite_response
8386
84- def get_env (self ):
85- return self ._realize_rendered_template (sp .environment )
86-
8787 def get_request_headers_override (self ):
8888 return self ._realize_rendered_template (sp .request_headers_override )
8989
90+ # these two methods are only used in supervise classes, but do no harm otherwise
91+ def get_env (self ):
92+ return self ._realize_rendered_template (sp .environment )
93+
9094 def get_timeout (self ):
9195 return sp .timeout
9296
@@ -108,24 +112,14 @@ def make_handlers(base_url, server_processes):
108112 """
109113 handlers = []
110114 for sp in server_processes :
111- if sp .command :
112- handler = _make_supervisedproxy_handler (sp )
113- kwargs = dict (state = {})
114- else :
115- if not (sp .port or isinstance (sp .unix_socket , str )):
116- warn (
117- f"Server proxy { sp .name } does not have a command, port "
118- f"number or unix_socket path. At least one of these is "
119- f"required."
120- )
121- continue
122- handler = _make_namedproxy_handler (sp )
123- kwargs = {}
115+ handler = _make_proxy_handler (sp )
116+ if not handler :
117+ continue
124118 handlers .append (
125119 (
126120 ujoin (base_url , sp .name , r"(.*)" ),
127121 handler ,
128- kwargs ,
122+ handler . kwargs
129123 )
130124 )
131125 handlers .append ((ujoin (base_url , sp .name ), AddSlashHandler ))
@@ -157,6 +151,7 @@ def make_server_process(name, server_process_config, serverproxy_config):
157151 "rewrite_response" ,
158152 tuple (),
159153 ),
154+ websockify = server_process_config .get ("websockify" , False ),
160155 )
161156
162157
@@ -273,6 +268,12 @@ def cats_only(response, path):
273268 instead of "dogs not allowed".
274269
275270 Defaults to the empty tuple ``tuple()``.
271+
272+ websockify
273+ Proxy websocket requests as a TCP (or unix socket) stream.
274+ In this mode, only websockets are handled, and messages are sent to the backend,
275+ equivalent to running a websockify layer (https://github.com/novnc/websockify).
276+ All other HTTP requests return 405.
276277 """ ,
277278 config = True ,
278279 )
0 commit comments