@@ -37,7 +37,13 @@ import (
37
37
// TODO move to API machinery and re-unify with kubelet/server/portfoward
38
38
const PortForwardProtocolV1Name = "portforward.k8s.io"
39
39
40
- var ErrLostConnectionToPod = errors .New ("lost connection to pod" )
40
+ var (
41
+ // error returned whenever we lost connection to a pod
42
+ ErrLostConnectionToPod = errors .New ("lost connection to pod" )
43
+
44
+ // set of error we're expecting during port-forwarding
45
+ networkClosedError = "use of closed network connection"
46
+ )
41
47
42
48
// PortForwarder knows how to listen for local connections and forward them to
43
49
// a remote pod via an upgraded HTTP request.
@@ -312,7 +318,7 @@ func (pf *PortForwarder) waitForConnection(listener net.Listener, port Forwarded
312
318
conn , err := listener .Accept ()
313
319
if err != nil {
314
320
// TODO consider using something like https://github.com/hydrogen18/stoppableListener?
315
- if ! strings .Contains (strings .ToLower (err .Error ()), "use of closed network connection" ) {
321
+ if ! strings .Contains (strings .ToLower (err .Error ()), networkClosedError ) {
316
322
runtime .HandleError (fmt .Errorf ("error accepting connection on port %d: %v" , port .Local , err ))
317
323
}
318
324
return
@@ -381,7 +387,7 @@ func (pf *PortForwarder) handleConnection(conn net.Conn, port ForwardedPort) {
381
387
382
388
go func () {
383
389
// Copy from the remote side to the local port.
384
- if _ , err := io .Copy (conn , dataStream ); err != nil && ! strings .Contains (err .Error (), "use of closed network connection" ) {
390
+ if _ , err := io .Copy (conn , dataStream ); err != nil && ! strings .Contains (strings . ToLower ( err .Error ()), networkClosedError ) {
385
391
runtime .HandleError (fmt .Errorf ("error copying from remote stream to local connection: %v" , err ))
386
392
}
387
393
@@ -394,7 +400,7 @@ func (pf *PortForwarder) handleConnection(conn net.Conn, port ForwardedPort) {
394
400
defer dataStream .Close ()
395
401
396
402
// Copy from the local port to the remote side.
397
- if _ , err := io .Copy (dataStream , conn ); err != nil && ! strings .Contains (err .Error (), "use of closed network connection" ) {
403
+ if _ , err := io .Copy (dataStream , conn ); err != nil && ! strings .Contains (strings . ToLower ( err .Error ()), networkClosedError ) {
398
404
runtime .HandleError (fmt .Errorf ("error copying from local connection to remote stream: %v" , err ))
399
405
// break out of the select below without waiting for the other copy to finish
400
406
close (localError )
@@ -407,6 +413,11 @@ func (pf *PortForwarder) handleConnection(conn net.Conn, port ForwardedPort) {
407
413
case <- localError :
408
414
}
409
415
416
+ // reset dataStream to discard any unsent data, preventing port forwarding from being blocked.
417
+ // we must reset dataStream before waiting on errorChan, otherwise,
418
+ // the blocking data will affect errorStream and cause <-errorChan to block indefinitely.
419
+ _ = dataStream .Reset ()
420
+
410
421
// always expect something on errorChan (it may be nil)
411
422
err = <- errorChan
412
423
if err != nil {
0 commit comments