@@ -31,60 +31,16 @@ def get(self, *args):
3131class ProxyHandler (WebSocketHandlerMixin , IPythonHandler ):
3232 """
3333 A tornado request handler that proxies HTTP and websockets from
34- a given host/port combination.
34+ a given host/port combination. This class is not meant to be
35+ used directly as a means of overriding CORS. This presents significant
36+ security risks, and could allow arbitrary remote code access. Instead, it is
37+ meant to be subclassed and used for proxying URLs from trusted sources.
3538 """
3639 def __init__ (self , * args , ** kwargs ):
3740 self .proxy_base = ''
3841 self .absolute_url = kwargs .pop ('absolute_url' , False )
3942 super ().__init__ (* args , ** kwargs )
4043
41- async def open (self , host , port , proxied_path = '' ):
42- """
43- Called when a client opens a websocket connection.
44-
45- We establish a websocket connection to the proxied backend &
46- set up a callback to relay messages through.
47- """
48- if not proxied_path .startswith ('/' ):
49- proxied_path = '/' + proxied_path
50-
51- client_uri = self .get_client_uri ('ws' , host , port , proxied_path )
52- headers = self .request .headers
53-
54- def message_cb (message ):
55- """
56- Callback when the backend sends messages to us
57-
58- We just pass it back to the frontend
59- """
60- # Websockets support both string (utf-8) and binary data, so let's
61- # make sure we signal that appropriately when proxying
62- self ._record_activity ()
63- if message is None :
64- self .close ()
65- else :
66- self .write_message (message , binary = isinstance (message , bytes ))
67-
68- def ping_cb (data ):
69- """
70- Callback when the backend sends pings to us.
71-
72- We just pass it back to the frontend.
73- """
74- self ._record_activity ()
75- self .ping (data )
76-
77- async def start_websocket_connection ():
78- self .log .info ('Trying to establish websocket connection to {}' .format (client_uri ))
79- self ._record_activity ()
80- request = httpclient .HTTPRequest (url = client_uri , headers = headers )
81- self .ws = await pingable_ws_connect (request = request ,
82- on_message_callback = message_cb , on_ping_callback = ping_cb )
83- self ._record_activity ()
84- self .log .info ('Websocket connection established to {}' .format (client_uri ))
85-
86- ioloop .IOLoop .current ().add_callback (start_websocket_connection )
87-
8844 def on_message (self , message ):
8945 """
9046 Called when we receive a message from our client.
@@ -232,6 +188,54 @@ async def proxy(self, host, port, proxied_path):
232188 if response .body :
233189 self .write (response .body )
234190
191+ async def proxy_open (self , host , port , proxied_path = '' ):
192+ """
193+ Called when a client opens a websocket connection.
194+
195+ We establish a websocket connection to the proxied backend &
196+ set up a callback to relay messages through.
197+ """
198+ if not proxied_path .startswith ('/' ):
199+ proxied_path = '/' + proxied_path
200+
201+ client_uri = self .get_client_uri ('ws' , host , port , proxied_path )
202+ headers = self .request .headers
203+
204+ def message_cb (message ):
205+ """
206+ Callback when the backend sends messages to us
207+
208+ We just pass it back to the frontend
209+ """
210+ # Websockets support both string (utf-8) and binary data, so let's
211+ # make sure we signal that appropriately when proxying
212+ self ._record_activity ()
213+ if message is None :
214+ self .close ()
215+ else :
216+ self .write_message (message , binary = isinstance (message , bytes ))
217+
218+ def ping_cb (data ):
219+ """
220+ Callback when the backend sends pings to us.
221+
222+ We just pass it back to the frontend.
223+ """
224+ self ._record_activity ()
225+ self .ping (data )
226+
227+ async def start_websocket_connection ():
228+ self .log .info ('Trying to establish websocket connection to {}' .format (client_uri ))
229+ self ._record_activity ()
230+ request = httpclient .HTTPRequest (url = client_uri , headers = headers )
231+ self .ws = await pingable_ws_connect (request = request ,
232+ on_message_callback = message_cb , on_ping_callback = ping_cb )
233+ self ._record_activity ()
234+ self .log .info ('Websocket connection established to {}' .format (client_uri ))
235+
236+ ioloop .IOLoop .current ().add_callback (start_websocket_connection )
237+
238+
235239 def proxy_request_headers (self ):
236240 '''A dictionary of headers to be used when constructing
237241 a tornado.httpclient.HTTPRequest instance for the proxy request.'''
@@ -293,7 +297,7 @@ async def http_get(self, port, proxied_path):
293297 return await self .proxy (port , proxied_path )
294298
295299 async def open (self , port , proxied_path ):
296- return await super (). open ('localhost' , port , proxied_path )
300+ return await self . proxy_open ('localhost' , port , proxied_path )
297301
298302 def post (self , port , proxied_path ):
299303 return self .proxy (port , proxied_path )
0 commit comments