Ready-to-use SRT / WebRTC / RTSP / RTMP / LL-HLS media server and media proxy that allows to read, publish, proxy, record and playback video and audio streams.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

102 lines
2.1 KiB

// Package httpserv contains HTTP server utilities.
package httpserv
import (
"context"
"crypto/tls"
"fmt"
"log"
"net"
"net/http"
"os"
"runtime"
"time"
"github.com/bluenviron/mediamtx/internal/conf"
)
type nilWriter struct{}
func (nilWriter) Write(p []byte) (int, error) {
return len(p), nil
}
// exit when there's a panic inside the HTTP handler.
// https://github.com/golang/go/issues/16542
type exitOnPanicHandler struct {
http.Handler
}
func (h exitOnPanicHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
defer func() {
err := recover()
if err != nil {
buf := make([]byte, 1<<20)
n := runtime.Stack(buf, true)
fmt.Fprintf(os.Stderr, "panic: %v\n\n%s", err, buf[:n])
os.Exit(1)
}
}()
h.Handler.ServeHTTP(w, r)
}
// 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
}
// NewWrappedServer allocates a WrappedServer.
func NewWrappedServer(
network string,
address string,
readTimeout conf.StringDuration,
serverCert string,
serverKey string,
handler http.Handler,
) (*WrappedServer, error) {
ln, err := net.Listen(network, address)
if err != nil {
return nil, err
}
var tlsConfig *tls.Config
if serverCert != "" {
crt, err := tls.LoadX509KeyPair(serverCert, serverKey)
if err != nil {
ln.Close()
return nil, err
}
tlsConfig = &tls.Config{
Certificates: []tls.Certificate{crt},
}
}
s := &WrappedServer{
ln: ln,
inner: &http.Server{
Handler: exitOnPanicHandler{handler},
TLSConfig: tlsConfig,
ReadHeaderTimeout: time.Duration(readTimeout),
ErrorLog: log.New(&nilWriter{}, "", 0),
},
}
if tlsConfig != nil {
go s.inner.ServeTLS(s.ln, "", "")
} else {
go s.inner.Serve(s.ln)
}
return s, nil
}
// 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()
}