aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorShulhan <ms@kilabit.info>2026-02-15 12:44:24 +0700
committerShulhan <ms@kilabit.info>2026-02-15 12:45:13 +0700
commit1844b9e48d0f5f7f3e9c8de026181d04d74c92ab (patch)
tree967889384daa96e58fdefd6315e134ab8029a2e7 /lib
parentccc9926635c1702337ac6fd1038bd7b903afa7f9 (diff)
downloadpakakeh.go-1844b9e48d0f5f7f3e9c8de026181d04d74c92ab.tar.xz
lib/http: fix possible data race in SSE connection
When server's handler call Write or WriteRaw, there is possibility that the worker for keeping the connection alive also call Write at the same time, which cause the data race.
Diffstat (limited to 'lib')
-rw-r--r--lib/http/sse_conn.go11
1 files changed, 9 insertions, 2 deletions
diff --git a/lib/http/sse_conn.go b/lib/http/sse_conn.go
index 055a5793..8d2f0b76 100644
--- a/lib/http/sse_conn.go
+++ b/lib/http/sse_conn.go
@@ -10,6 +10,7 @@ import (
"net"
"net/http"
"strings"
+ "sync"
"time"
)
@@ -28,6 +29,10 @@ type SSEConn struct {
bufrw *bufio.ReadWriter
conn net.Conn
+
+ // bufrwMtx protects the concurrent write between client and
+ // workerKeepAlive.
+ bufrwMtx sync.Mutex
}
// WriteEvent write message with optional event type and id to client.
@@ -61,21 +66,23 @@ func (ep *SSEConn) WriteEvent(event, data string, id *string) (err error) {
ep.writeData(&buf, data, id)
- _, err = ep.bufrw.Write(buf.Bytes())
+ err = ep.WriteRaw(buf.Bytes())
if err != nil {
return fmt.Errorf(`WriteEvent: %w`, err)
}
- ep.bufrw.Flush()
return nil
}
// WriteRaw write raw event message directly, without any parsing.
func (ep *SSEConn) WriteRaw(msg []byte) (err error) {
+ ep.bufrwMtx.Lock()
_, err = ep.bufrw.Write(msg)
if err != nil {
+ ep.bufrwMtx.Unlock()
return fmt.Errorf(`WriteRaw: %w`, err)
}
ep.bufrw.Flush()
+ ep.bufrwMtx.Unlock()
return nil
}