@@ -237,30 +237,30 @@ def __init__(self, websocket, ports):
237237 """
238238
239239 self .websocket = websocket
240- self .ports = {}
241- for ix , port_number in enumerate (ports ):
242- self .ports [ port_number ] = self ._Port (ix , port_number )
240+ self .local_ports = {}
241+ for ix , local_remote in enumerate (ports ):
242+ self .local_ports [ local_remote [ 0 ]] = self ._Port (ix , local_remote [ 1 ] )
243243 threading .Thread (
244244 name = "Kubernetes port forward proxy" , target = self ._proxy , daemon = True
245245 ).start ()
246246
247- def socket (self , port_number ):
248- if port_number not in self .ports :
247+ def socket (self , local_number ):
248+ if local_number not in self .local_ports :
249249 raise ValueError ("Invalid port number" )
250- return self .ports [ port_number ].socket
250+ return self .local_ports [ local_number ].socket
251251
252- def error_channel (self , port_number ):
253- if port_number not in self .ports :
252+ def error (self , local_number ):
253+ if local_number not in self .local_ports :
254254 raise ValueError ("Invalid port number" )
255- return self .ports [ port_number ].error
255+ return self .local_ports [ local_number ].error
256256
257257 def close (self ):
258- for port in self .ports .values ():
258+ for port in self .local_ports .values ():
259259 port .socket .close ()
260260
261261 class _Port :
262- def __init__ (self , ix , number ):
263- self .number = number
262+ def __init__ (self , ix , remote_number ):
263+ self .remote_number = remote_number
264264 self .channel = bytes ([ix * 2 ])
265265 s , self .python = socket .socketpair (socket .AF_UNIX , socket .SOCK_STREAM )
266266 self .socket = self ._Socket (s )
@@ -287,7 +287,7 @@ def _proxy(self):
287287 channel_initialized = []
288288 python_ports = {}
289289 rlist = []
290- for port in self .ports .values ():
290+ for port in self .local_ports .values ():
291291 # Setup the data channel for this port number
292292 channel_ports .append (port )
293293 channel_initialized .append (False )
@@ -300,7 +300,7 @@ def _proxy(self):
300300 kubernetes_data = b''
301301 while True :
302302 wlist = []
303- for port in self .ports .values ():
303+ for port in self .local_ports .values ():
304304 if port .data :
305305 wlist .append (port .python )
306306 if kubernetes_data :
@@ -318,7 +318,7 @@ def _proxy(self):
318318 if s == self .websocket .sock :
319319 opcode , frame = self .websocket .recv_data_frame (True )
320320 if opcode == ABNF .OPCODE_CLOSE :
321- for port in self .ports .values ():
321+ for port in self .local_ports .values ():
322322 port .python .close ()
323323 return
324324 if opcode == ABNF .OPCODE_BINARY :
@@ -330,11 +330,9 @@ def _proxy(self):
330330 port = channel_ports [channel ]
331331 if channel_initialized [channel ]:
332332 if channel % 2 :
333- port .error = frame .data [1 :].decode ()
334- if port .python in rlist :
335- port .python .close ()
336- rlist .remove (port .python )
337- port .data = b''
333+ if port .error is None :
334+ port .error = ''
335+ port .error += frame .data [1 :].decode ()
338336 else :
339337 port .data += frame .data [1 :]
340338 else :
@@ -343,7 +341,7 @@ def _proxy(self):
343341 "Unexpected initial channel frame data size"
344342 )
345343 port_number = frame .data [1 ] + (frame .data [2 ] * 256 )
346- if port_number != port .number :
344+ if port_number != port .remote_number :
347345 raise RuntimeError (
348346 "Unexpected port number in initial channel frame: " + str (port_number )
349347 )
@@ -453,17 +451,38 @@ def portforward_call(configuration, _method, url, **kwargs):
453451 query_params = kwargs .get ("query_params" )
454452
455453 ports = []
456- for key , value in query_params :
457- if key == 'ports' :
458- for port in value .split (',' ):
454+ for ix in range (len (query_params )):
455+ if query_params [ix ][0 ] == 'ports' :
456+ remote_ports = []
457+ for port in query_params [ix ][1 ].split (',' ):
459458 try :
460- # The last specified port is the remote port
461- port = int (port .split (':' )[- 1 ])
462- if not (0 < port < 65536 ):
459+ local_remote = port .split (':' )
460+ if len (local_remote ) > 2 :
463461 raise ValueError
464- ports .append (port )
462+ if len (local_remote ) == 1 :
463+ local_remote [0 ] = int (local_remote [0 ])
464+ if not (0 < local_remote [0 ] < 65536 ):
465+ raise ValueError
466+ local_remote .append (local_remote [0 ])
467+ elif len (local_remote ) == 2 :
468+ if local_remote [0 ]:
469+ local_remote [0 ] = int (local_remote [0 ])
470+ if not (0 <= local_remote [0 ] < 65536 ):
471+ raise ValueError
472+ else :
473+ local_remote [0 ] = 0
474+ local_remote [1 ] = int (local_remote [1 ])
475+ if not (0 < local_remote [1 ] < 65536 ):
476+ raise ValueError
477+ if not local_remote [0 ]:
478+ local_remote [0 ] = len (ports ) + 1
479+ else :
480+ raise ValueError
481+ ports .append (local_remote )
482+ remote_ports .append (str (local_remote [1 ]))
465483 except ValueError :
466- raise ApiValueError ("Invalid port number `" + str (port ) + "`" )
484+ raise ApiValueError ("Invalid port number `" + port + "`" )
485+ query_params [ix ] = ('ports' , ',' .join (remote_ports ))
467486 if not ports :
468487 raise ApiValueError ("Missing required parameter `ports`" )
469488
0 commit comments