Fixed ws dial input error being dropped

This commit is contained in:
bwilliams committed 2026-10-16 08:52:45 +01:00
1 parent 02e3d910a2
commit b714ee14d5
2 files changed
+38 -1

No files matched your search

+9 -1
View File
@@ -321,14 +321,17 @@ func interact(
}() }()
// Reading input can't be interrupted, so it has a goroutine of its own, // Reading input can't be interrupted, so it has a goroutine of its own,
// left blocked if ctx is cancelled first. // left blocked if ctx is cancelled first. Its error, if any, is sent
// before lines is closed.
lines := make(chan string) lines := make(chan string)
inputErr := make(chan error, 1)
go func() { go func() {
defer close(lines) defer close(lines)
scanner := bufio.NewScanner(input) scanner := bufio.NewScanner(input)
for scanner.Scan() { for scanner.Scan() {
lines <- scanner.Text() lines <- scanner.Text()
} }
inputErr <- scanner.Err()
}() }()
for { for {
@@ -339,6 +342,11 @@ func interact(
return err return err
case line, ok := <-lines: case line, ok := <-lines:
if !ok { if !ok {
err := <-inputErr
if err != nil {
return fmt.Errorf("reading input: %w", err)
}
// The end of input: stop sending, keep listening. // The end of input: stop sending, keep listening.
lines = nil lines = nil
continue continue
+29
View File
@@ -3,6 +3,7 @@ package ws
import ( import (
"bytes" "bytes"
"context" "context"
"errors"
"io" "io"
"log/slog" "log/slog"
"net/http" "net/http"
@@ -281,6 +282,34 @@ func TestDialStdin(t *testing.T) {
} }
} }
// Without --message, a failure reading stdin ends dial with an error, unlike
// the end of stdin.
func TestDialStdinError(t *testing.T) {
_, url := wsServer(t)
stdin, input := io.Pipe()
out := &syncBuffer{}
done := make(chan error, 1)
go func() {
done <- dial(context.Background(), stdin, out, dialSettings{
url: url,
timeout: time.Second,
})
}()
waitFor(t, out, `< {"type":"welcome"`)
input.CloseWithError(errors.New("disk on fire"))
select {
case err := <-done:
if err == nil || !strings.Contains(err.Error(), "reading input: disk on fire") {
t.Fatalf("dial = %v; want the input error", err)
}
case <-time.After(time.Second):
t.Fatal("dial did not return after the input error")
}
}
// Without --message, dial ends when the server closes the connection. // Without --message, dial ends when the server closes the connection.
func TestDialStdinServerClose(t *testing.T) { func TestDialStdinServerClose(t *testing.T) {
hub, url := wsServer(t) hub, url := wsServer(t)