move HTTP utilities in a dedicated package (#2123)

needed by #2068
This commit is contained in:
Alessandro Ros 2023-07-30 23:03:00 +02:00 committed by GitHub
parent 08d6d0b888
commit 119d6abf19
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 91 additions and 71 deletions

View File

@ -55,3 +55,12 @@ func (d *IPsOrCIDRs) UnmarshalEnv(s string) error {
byts, _ := json.Marshal(strings.Split(s, ","))
return d.UnmarshalJSON(byts)
}
// ToTrustedProxies converts IPsOrCIDRs into a string slice for SetTrustedProxies.
func (d *IPsOrCIDRs) ToTrustedProxies() []string {
ret := make([]string, len(*d))
for i, entry := range *d {
ret[i] = entry.String()
}
return ret
}

View File

@ -12,6 +12,7 @@ import (
"github.com/google/uuid"
"github.com/bluenviron/mediamtx/internal/conf"
"github.com/bluenviron/mediamtx/internal/httpserv"
"github.com/bluenviron/mediamtx/internal/logger"
)
@ -195,7 +196,7 @@ type api struct {
webRTCManager apiWebRTCManager
parent apiParent
httpServer *httpServer
httpServer *httpserv.WrappedServer
mutex sync.Mutex
}
@ -227,9 +228,9 @@ func newAPI(
router := gin.New()
router.SetTrustedProxies(nil)
mwLog := httpLoggerMiddleware(a)
router.NoRoute(mwLog, httpServerHeaderMiddleware)
group := router.Group("/", mwLog, httpServerHeaderMiddleware)
mwLog := httpserv.MiddlewareLogger(a)
router.NoRoute(mwLog, httpserv.MiddlewareServerHeader)
group := router.Group("/", mwLog, httpserv.MiddlewareServerHeader)
group.GET("/v2/config/get", a.onConfigGet)
group.POST("/v2/config/set", a.onConfigSet)
@ -279,8 +280,11 @@ func newAPI(
group.POST("/v2/webrtcsessions/kick/:id", a.onWebRTCSessionsKick)
}
network, address := restrictNetwork("tcp", address)
var err error
a.httpServer, err = newHTTPServer(
a.httpServer, err = httpserv.NewWrappedServer(
network,
address,
readTimeout,
"",
@ -298,7 +302,7 @@ func newAPI(
func (a *api) close() {
a.Log(logger.Info, "listener is closing")
a.httpServer.close()
a.httpServer.Close()
}
func (a *api) Log(level logger.Level, format string, args ...interface{}) {

View File

@ -12,6 +12,7 @@ import (
"github.com/gin-gonic/gin"
"github.com/bluenviron/mediamtx/internal/conf"
"github.com/bluenviron/mediamtx/internal/httpserv"
"github.com/bluenviron/mediamtx/internal/logger"
)
@ -32,7 +33,7 @@ type hlsHTTPServer struct {
pathManager *pathManager
parent hlsHTTPServerParent
inner *httpServer
inner *httpserv.WrappedServer
}
func newHLSHTTPServer( //nolint:dupl
@ -62,12 +63,15 @@ func newHLSHTTPServer( //nolint:dupl
}
router := gin.New()
httpSetTrustedProxies(router, trustedProxies)
router.SetTrustedProxies(trustedProxies.ToTrustedProxies())
router.NoRoute(httpLoggerMiddleware(s), httpServerHeaderMiddleware, s.onRequest)
router.NoRoute(httpserv.MiddlewareLogger(s), httpserv.MiddlewareServerHeader, s.onRequest)
network, address := restrictNetwork("tcp", address)
var err error
s.inner, err = newHTTPServer(
s.inner, err = httpserv.NewWrappedServer(
network,
address,
readTimeout,
serverCert,
@ -86,7 +90,7 @@ func (s *hlsHTTPServer) Log(level logger.Level, format string, args ...interface
}
func (s *hlsHTTPServer) close() {
s.inner.close()
s.inner.Close()
}
func (s *hlsHTTPServer) onRequest(ctx *gin.Context) {

View File

@ -131,7 +131,7 @@ func newHLSManager(
m.pathManager.hlsManagerSet(m)
if m.metrics != nil {
m.metrics.hlsManagerSet(m)
m.metrics.setHLSManager(m)
}
m.wg.Add(1)
@ -226,7 +226,7 @@ outer:
m.pathManager.hlsManagerSet(nil)
if m.metrics != nil {
m.metrics.hlsManagerSet(nil)
m.metrics.setHLSManager(nil)
}
}

View File

@ -1,10 +0,0 @@
package core
import (
"github.com/gin-gonic/gin"
)
func httpServerHeaderMiddleware(ctx *gin.Context) {
ctx.Writer.Header().Set("Server", "mediamtx")
ctx.Next()
}

View File

@ -1,15 +0,0 @@
package core
import (
"github.com/gin-gonic/gin"
"github.com/bluenviron/mediamtx/internal/conf"
)
func httpSetTrustedProxies(router *gin.Engine, trustedProxies conf.IPsOrCIDRs) {
tmp := make([]string, len(trustedProxies))
for i, entry := range trustedProxies {
tmp[i] = entry.String()
}
router.SetTrustedProxies(tmp)
}

View File

@ -9,6 +9,7 @@ import (
"github.com/gin-gonic/gin"
"github.com/bluenviron/mediamtx/internal/conf"
"github.com/bluenviron/mediamtx/internal/httpserv"
"github.com/bluenviron/mediamtx/internal/logger"
)
@ -23,7 +24,7 @@ type metricsParent interface {
type metrics struct {
parent metricsParent
httpServer *httpServer
httpServer *httpserv.WrappedServer
mutex sync.Mutex
pathManager apiPathManager
rtspServer apiRTSPServer
@ -45,12 +46,15 @@ func newMetrics(
router := gin.New()
router.SetTrustedProxies(nil)
mwLog := httpLoggerMiddleware(m)
mwLog := httpserv.MiddlewareLogger(m)
router.NoRoute(mwLog)
router.GET("/metrics", mwLog, m.onMetrics)
network, address := restrictNetwork("tcp", address)
var err error
m.httpServer, err = newHTTPServer(
m.httpServer, err = httpserv.NewWrappedServer(
network,
address,
readTimeout,
"",
@ -68,7 +72,7 @@ func newMetrics(
func (m *metrics) close() {
m.Log(logger.Info, "listener is closing")
m.httpServer.close()
m.httpServer.Close()
}
func (m *metrics) Log(level logger.Level, format string, args ...interface{}) {
@ -221,8 +225,8 @@ func (m *metrics) pathManagerSet(s apiPathManager) {
m.pathManager = s
}
// hlsManagerSet is called by hlsManager.
func (m *metrics) hlsManagerSet(s apiHLSManager) {
// setHLSManager is called by hlsManager.
func (m *metrics) setHLSManager(s apiHLSManager) {
m.mutex.Lock()
defer m.mutex.Unlock()
m.hlsManager = s

View File

@ -7,6 +7,7 @@ import (
_ "net/http/pprof"
"github.com/bluenviron/mediamtx/internal/conf"
"github.com/bluenviron/mediamtx/internal/httpserv"
"github.com/bluenviron/mediamtx/internal/logger"
)
@ -17,7 +18,7 @@ type pprofParent interface {
type pprof struct {
parent pprofParent
httpServer *httpServer
httpServer *httpserv.WrappedServer
}
func newPPROF(
@ -29,8 +30,11 @@ func newPPROF(
parent: parent,
}
network, address := restrictNetwork("tcp", address)
var err error
pp.httpServer, err = newHTTPServer(
pp.httpServer, err = httpserv.NewWrappedServer(
network,
address,
readTimeout,
"",
@ -48,7 +52,7 @@ func newPPROF(
func (pp *pprof) close() {
pp.Log(logger.Info, "listener is closing")
pp.httpServer.close()
pp.httpServer.Close()
}
func (pp *pprof) Log(level logger.Level, format string, args ...interface{}) {

View File

@ -18,6 +18,7 @@ import (
"github.com/pion/webrtc/v3"
"github.com/bluenviron/mediamtx/internal/conf"
"github.com/bluenviron/mediamtx/internal/httpserv"
"github.com/bluenviron/mediamtx/internal/logger"
)
@ -170,7 +171,7 @@ type webRTCHTTPServer struct {
pathManager *pathManager
parent webRTCHTTPServerParent
inner *httpServer
inner *httpserv.WrappedServer
}
func newWebRTCHTTPServer( //nolint:dupl
@ -200,11 +201,14 @@ func newWebRTCHTTPServer( //nolint:dupl
}
router := gin.New()
httpSetTrustedProxies(router, trustedProxies)
router.NoRoute(httpLoggerMiddleware(s), httpServerHeaderMiddleware, s.onRequest)
router.SetTrustedProxies(trustedProxies.ToTrustedProxies())
router.NoRoute(httpserv.MiddlewareLogger(s), httpserv.MiddlewareServerHeader, s.onRequest)
network, address := restrictNetwork("tcp", address)
var err error
s.inner, err = newHTTPServer(
s.inner, err = httpserv.NewWrappedServer(
network,
address,
readTimeout,
serverCert,
@ -223,7 +227,7 @@ func (s *webRTCHTTPServer) Log(level logger.Level, format string, args ...interf
}
func (s *webRTCHTTPServer) close() {
s.inner.close()
s.inner.Close()
}
func (s *webRTCHTTPServer) onRequest(ctx *gin.Context) {

View File

@ -1,4 +1,4 @@
package core
package httpserv
import (
"bytes"
@ -11,22 +11,22 @@ import (
"github.com/bluenviron/mediamtx/internal/logger"
)
type httpLoggerWriter struct {
type loggerWriter struct {
gin.ResponseWriter
buf bytes.Buffer
}
func (w *httpLoggerWriter) Write(b []byte) (int, error) {
func (w *loggerWriter) Write(b []byte) (int, error) {
w.buf.Write(b)
return w.ResponseWriter.Write(b)
}
func (w *httpLoggerWriter) WriteString(s string) (int, error) {
func (w *loggerWriter) WriteString(s string) (int, error) {
w.buf.WriteString(s)
return w.ResponseWriter.WriteString(s)
}
func (w *httpLoggerWriter) dump() string {
func (w *loggerWriter) dump() string {
var buf bytes.Buffer
fmt.Fprintf(&buf, "%s %d %s\n", "HTTP/1.1", w.ResponseWriter.Status(), http.StatusText(w.ResponseWriter.Status()))
w.ResponseWriter.Header().Write(&buf)
@ -37,18 +37,15 @@ func (w *httpLoggerWriter) dump() string {
return buf.String()
}
type httpLoggerParent interface {
logger.Writer
}
func httpLoggerMiddleware(p httpLoggerParent) func(*gin.Context) {
// MiddlewareLogger is a middleware that logs requests and responses.
func MiddlewareLogger(p logger.Writer) func(*gin.Context) {
return func(ctx *gin.Context) {
p.Log(logger.Debug, "[conn %v] %s %s", ctx.Request.RemoteAddr, ctx.Request.Method, ctx.Request.URL.Path)
byts, _ := httputil.DumpRequest(ctx.Request, true)
p.Log(logger.Debug, "[conn %v] [c->s] %s", ctx.Request.RemoteAddr, string(byts))
logw := &httpLoggerWriter{ResponseWriter: ctx.Writer}
logw := &loggerWriter{ResponseWriter: ctx.Writer}
ctx.Writer = logw
ctx.Next()

View File

@ -0,0 +1,11 @@
package httpserv
import (
"github.com/gin-gonic/gin"
)
// MiddlewareServerHeader is a middleware that sets the Server header.
func MiddlewareServerHeader(ctx *gin.Context) {
ctx.Writer.Header().Set("Server", "mediamtx")
ctx.Next()
}

View File

@ -1,4 +1,5 @@
package core
// Package httpserv contains HTTP server utilities.
package httpserv
import (
"context"
@ -20,7 +21,7 @@ func (nilWriter) Write(p []byte) (int, error) {
return len(p), nil
}
// exit when there's a panic inside HTTP handlers.
// exit when there's a panic inside the HTTP handler.
// https://github.com/golang/go/issues/16542
type exitOnPanicHandler struct {
http.Handler
@ -39,19 +40,25 @@ func (h exitOnPanicHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
h.Handler.ServeHTTP(w, r)
}
type httpServer struct {
// WrappedServer is a wrapper around http.Server that provides:
// - net.Listener allocation and closure
// - TLS allocation
// - exit on panic
type WrappedServer struct {
ln net.Listener
inner *http.Server
}
func newHTTPServer(
// NewWrappedServer allocates a WrappedServer.
func NewWrappedServer(
network string,
address string,
readTimeout conf.StringDuration,
serverCert string,
serverKey string,
handler http.Handler,
) (*httpServer, error) {
ln, err := net.Listen(restrictNetwork("tcp", address))
) (*WrappedServer, error) {
ln, err := net.Listen(network, address)
if err != nil {
return nil, err
}
@ -69,7 +76,7 @@ func newHTTPServer(
}
}
s := &httpServer{
s := &WrappedServer{
ln: ln,
inner: &http.Server{
Handler: exitOnPanicHandler{handler},
@ -88,7 +95,8 @@ func newHTTPServer(
return s, nil
}
func (s *httpServer) close() {
// Close closes all resources and waits for all routines to return.
func (s *WrappedServer) Close() {
s.inner.Shutdown(context.Background())
s.ln.Close() // in case Shutdown() is called before Serve()
}