Add support for HTTP over unix sockets (#4241)

This adds support for using unix scheme in xxxAddress config options.
For example `hlsAddress: "unix://hls.sock"`.

---------

Co-authored-by: aler9 <46489434+aler9@users.noreply.github.com>
This commit is contained in:
krystiancha
2025-08-03 12:30:26 +02:00
committed by GitHub
co-authored by aler9
parent bfdd4f81bd
commit 6ffa07e8e8
8 changed files with 81 additions and 44 deletions
+2 -6
View File
@@ -23,7 +23,6 @@ import (
"github.com/bluenviron/mediamtx/internal/logger"
"github.com/bluenviron/mediamtx/internal/protocols/httpp"
"github.com/bluenviron/mediamtx/internal/recordstore"
"github.com/bluenviron/mediamtx/internal/restrictnetwork"
"github.com/bluenviron/mediamtx/internal/servers/hls"
"github.com/bluenviron/mediamtx/internal/servers/rtmp"
"github.com/bluenviron/mediamtx/internal/servers/rtsp"
@@ -189,11 +188,8 @@ func (a *API) Initialize() error {
group.GET("/recordings/get/*name", a.onRecordingsGet)
group.DELETE("/recordings/deletesegment", a.onRecordingDeleteSegment)
network, address := restrictnetwork.Restrict("tcp", a.Address)
a.httpServer = &httpp.Server{
Network: network,
Address: address,
Address: a.Address,
ReadTimeout: time.Duration(a.ReadTimeout),
Encryption: a.Encryption,
ServerCert: a.ServerCert,
@@ -206,7 +202,7 @@ func (a *API) Initialize() error {
return err
}
a.Log(logger.Info, "listener opened on "+address)
a.Log(logger.Info, "listener opened on "+a.Address)
return nil
}
+2 -6
View File
@@ -18,7 +18,6 @@ import (
"github.com/bluenviron/mediamtx/internal/defs"
"github.com/bluenviron/mediamtx/internal/logger"
"github.com/bluenviron/mediamtx/internal/protocols/httpp"
"github.com/bluenviron/mediamtx/internal/restrictnetwork"
)
func interfaceIsEmpty(i interface{}) bool {
@@ -103,11 +102,8 @@ func (m *Metrics) Initialize() error {
router.GET("/metrics", m.onMetrics)
network, address := restrictnetwork.Restrict("tcp", m.Address)
m.httpServer = &httpp.Server{
Network: network,
Address: address,
Address: m.Address,
ReadTimeout: time.Duration(m.ReadTimeout),
Encryption: m.Encryption,
ServerCert: m.ServerCert,
@@ -120,7 +116,7 @@ func (m *Metrics) Initialize() error {
return err
}
m.Log(logger.Info, "listener opened on "+address)
m.Log(logger.Info, "listener opened on "+m.Address)
return nil
}
+2 -6
View File
@@ -11,7 +11,6 @@ import (
"github.com/bluenviron/mediamtx/internal/conf"
"github.com/bluenviron/mediamtx/internal/logger"
"github.com/bluenviron/mediamtx/internal/protocols/httpp"
"github.com/bluenviron/mediamtx/internal/restrictnetwork"
"github.com/gin-gonic/gin"
)
@@ -46,11 +45,8 @@ func (s *Server) Initialize() error {
router.GET("/list", s.onList)
router.GET("/get", s.onGet)
network, address := restrictnetwork.Restrict("tcp", s.Address)
s.httpServer = &httpp.Server{
Network: network,
Address: address,
Address: s.Address,
ReadTimeout: time.Duration(s.ReadTimeout),
Encryption: s.Encryption,
ServerCert: s.ServerCert,
@@ -63,7 +59,7 @@ func (s *Server) Initialize() error {
return err
}
s.Log(logger.Info, "listener opened on "+address)
s.Log(logger.Info, "listener opened on "+s.Address)
return nil
}
+2 -6
View File
@@ -13,7 +13,6 @@ import (
"github.com/bluenviron/mediamtx/internal/conf"
"github.com/bluenviron/mediamtx/internal/logger"
"github.com/bluenviron/mediamtx/internal/protocols/httpp"
"github.com/bluenviron/mediamtx/internal/restrictnetwork"
)
type pprofAuthManager interface {
@@ -49,11 +48,8 @@ func (pp *PPROF) Initialize() error {
pprof.Register(router)
network, address := restrictnetwork.Restrict("tcp", pp.Address)
pp.httpServer = &httpp.Server{
Network: network,
Address: address,
Address: pp.Address,
ReadTimeout: time.Duration(pp.ReadTimeout),
Encryption: pp.Encryption,
ServerCert: pp.ServerCert,
@@ -66,7 +62,7 @@ func (pp *PPROF) Initialize() error {
return err
}
pp.Log(logger.Info, "listener opened on "+address)
pp.Log(logger.Info, "listener opened on "+pp.Address)
return nil
}
+22 -2
View File
@@ -8,10 +8,13 @@ import (
"log"
"net"
"net/http"
"os"
"strings"
"time"
"github.com/bluenviron/mediamtx/internal/certloader"
"github.com/bluenviron/mediamtx/internal/logger"
"github.com/bluenviron/mediamtx/internal/restrictnetwork"
)
type nilWriter struct{}
@@ -28,7 +31,6 @@ func (nilWriter) Write(p []byte) (int, error) {
// - server header
// - filtering of invalid requests
type Server struct {
Network string
Address string
ReadTimeout time.Duration
Encryption bool
@@ -65,12 +67,30 @@ func (s *Server) Initialize() error {
}
}
var network string
var address string
if strings.HasPrefix(s.Address, "unix://") {
network = "unix"
address = s.Address[len("unix://"):]
} else {
network, address = restrictnetwork.Restrict("tcp", s.Address)
}
if network == "unix" {
os.Remove(address)
}
var err error
s.ln, err = net.Listen(s.Network, s.Address)
s.ln, err = net.Listen(network, address)
if err != nil {
return err
}
if network == "unix" {
os.Chmod(address, 0o755) //nolint:errcheck
}
h := s.Handler
h = &handlerFilterRequests{h}
h = &handlerFilterRequests{h}
+49 -8
View File
@@ -1,8 +1,10 @@
package httpp
import (
"io"
"net"
"net/http"
"os"
"strings"
"testing"
"time"
@@ -13,10 +15,12 @@ import (
func TestFilterEmptyPath(t *testing.T) {
s := &Server{
Network: "tcp",
Address: "localhost:4555",
ReadTimeout: 10 * time.Second,
Parent: test.NilLogger,
Handler: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusOK)
}),
}
err := s.Initialize()
require.NoError(t, err)
@@ -26,13 +30,50 @@ func TestFilterEmptyPath(t *testing.T) {
require.NoError(t, err)
defer conn.Close()
_, err = conn.Write([]byte("OPTIONS http://localhost HTTP/1.1\n" +
"Host: localhost:8889\n" +
"Accept-Encoding: gzip\n" +
"User-Agent: Go-http-client/1.1\n\n"))
_, err = conn.Write([]byte("OPTIONS / HTTP/1.1\n" +
"Host: localhost:8889\n\n"))
require.NoError(t, err)
buf := make([]byte, 20)
_, err = io.ReadFull(conn, buf)
buf := make([]byte, 200)
n, err := conn.Read(buf)
require.NoError(t, err)
res := strings.Split(string(buf[:n]), "\r\n")
require.Equal(t, "HTTP/1.1 200 OK", res[0])
}
func TestUnixSocket(t *testing.T) {
s := &Server{
Address: "unix://http.sock",
ReadTimeout: 10 * time.Second,
Parent: test.NilLogger,
Handler: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusOK)
}),
}
err := s.Initialize()
require.NoError(t, err)
_, err = os.Stat("http.sock")
require.NoError(t, err)
conn, err := net.Dial("unix", "http.sock")
require.NoError(t, err)
_, err = conn.Write([]byte("OPTIONS / HTTP/1.1\n" +
"Host: localhost:8889\n\n"))
require.NoError(t, err)
buf := make([]byte, 200)
n, err := conn.Read(buf)
require.NoError(t, err)
res := strings.Split(string(buf[:n]), "\r\n")
require.Equal(t, "HTTP/1.1 200 OK", res[0])
conn.Close()
s.Close()
_, err = os.Stat("http.sock")
require.EqualError(t, err, "stat http.sock: no such file or directory")
}
+1 -5
View File
@@ -16,7 +16,6 @@ import (
"github.com/bluenviron/mediamtx/internal/defs"
"github.com/bluenviron/mediamtx/internal/logger"
"github.com/bluenviron/mediamtx/internal/protocols/httpp"
"github.com/bluenviron/mediamtx/internal/restrictnetwork"
)
//go:generate go run ./hlsjsdownloader
@@ -57,11 +56,8 @@ func (s *httpServer) initialize() error {
router.Use(s.onRequest)
network, address := restrictnetwork.Restrict("tcp", s.address)
s.inner = &httpp.Server{
Network: network,
Address: address,
Address: s.address,
ReadTimeout: time.Duration(s.readTimeout),
Encryption: s.encryption,
ServerCert: s.serverCert,
+1 -5
View File
@@ -20,7 +20,6 @@ import (
"github.com/bluenviron/mediamtx/internal/logger"
"github.com/bluenviron/mediamtx/internal/protocols/httpp"
"github.com/bluenviron/mediamtx/internal/protocols/whip"
"github.com/bluenviron/mediamtx/internal/restrictnetwork"
)
//go:embed publish_index.html
@@ -94,11 +93,8 @@ func (s *httpServer) initialize() error {
router.Use(s.onRequest)
network, address := restrictnetwork.Restrict("tcp", s.address)
s.inner = &httpp.Server{
Network: network,
Address: address,
Address: s.address,
ReadTimeout: time.Duration(s.readTimeout),
Encryption: s.encryption,
ServerCert: s.serverCert,