summaryrefslogtreecommitdiff
path: root/internal/server_test.go
diff options
context:
space:
mode:
authorT <t@tjp.lol>2025-04-03 10:00:40 -0600
committert <t@tjp.lol>2026-07-01 10:47:36 -0600
commit748a806adc5a325e63ca6883b2aa9bf15da90513 (patch)
treea60cf2e32370f9e2cf194e8b52bcb2af3ed6a120 /internal/server_test.go
parent74bbf67ebbd1325ff699a052933ad94bc0401c58 (diff)
Harden Gopher parsing and recover server goroutinesHEADv1.6.4main
Reject oversized or malformed Gopher selectors as parse errors instead of panicking. Keep search requests bounded, and wrap shared server goroutines with panic logging so one bad connection cannot take down the process.
Diffstat (limited to 'internal/server_test.go')
-rw-r--r--internal/server_test.go66
1 files changed, 66 insertions, 0 deletions
diff --git a/internal/server_test.go b/internal/server_test.go
new file mode 100644
index 0000000..62d8681
--- /dev/null
+++ b/internal/server_test.go
@@ -0,0 +1,66 @@
+package internal_test
+
+import (
+ "context"
+ "fmt"
+ "net"
+ "strings"
+ "sync"
+ "testing"
+ "time"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+
+ "tildegit.org/tjp/sliderule/internal"
+)
+
+type captureLogger struct {
+ mu sync.Mutex
+ logs []string
+}
+
+func (cl *captureLogger) Log(keyvals ...any) error {
+ cl.mu.Lock()
+ defer cl.mu.Unlock()
+
+ for _, val := range keyvals {
+ cl.logs = append(cl.logs, fmt.Sprint(val))
+ }
+ return nil
+}
+
+func (cl *captureLogger) String() string {
+ cl.mu.Lock()
+ defer cl.mu.Unlock()
+
+ return strings.Join(cl.logs, " ")
+}
+
+func TestServerRecoversConnectionPanic(t *testing.T) {
+ var logs captureLogger
+ server, err := internal.NewServer(
+ context.Background(),
+ "localhost",
+ "tcp",
+ "127.0.0.1:0",
+ &logs,
+ func(net.Conn) { panic("boom") },
+ )
+ require.Nil(t, err)
+
+ done := make(chan error, 1)
+ go func() { done <- server.Serve() }()
+
+ conn, err := net.Dial(server.Network(), server.Address())
+ require.Nil(t, err)
+ _ = conn.Close()
+
+ require.Eventually(t, func() bool {
+ return strings.Contains(logs.String(), "panic in server goroutine")
+ }, time.Second, 10*time.Millisecond)
+
+ server.Close()
+ assert.Nil(t, <-done)
+ assert.Contains(t, logs.String(), "boom")
+}