diff options
| author | Shulhan <ms@kilabit.info> | 2026-02-15 12:44:24 +0700 |
|---|---|---|
| committer | Shulhan <ms@kilabit.info> | 2026-02-15 12:45:13 +0700 |
| commit | 1844b9e48d0f5f7f3e9c8de026181d04d74c92ab (patch) | |
| tree | 967889384daa96e58fdefd6315e134ab8029a2e7 | |
| parent | ccc9926635c1702337ac6fd1038bd7b903afa7f9 (diff) | |
| download | pakakeh.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.
| -rw-r--r-- | CHANGELOG.adoc | 7 | ||||
| -rw-r--r-- | lib/http/sse_conn.go | 11 |
2 files changed, 16 insertions, 2 deletions
diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 7f41b747..33f515c9 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -77,6 +77,13 @@ then shutting down. This allow de-activating HTTP server when no connections received after specific duration to reduce the system resources. +=== 🌼 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. + + //}}} [#v0_61_0] == pakakeh.go v0.61.0 (2026-02-09) 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 } |
