mirror of
https://github.com/aler9/rtsp-simple-server
synced 2025-10-05 07:36:57 +08:00
webrtc: return 404 in case a WHIP PATCH or WHIP DELETE request fails (#3232)
This commit is contained in:
@@ -236,7 +236,11 @@ func (s *httpServer) onWHIPPatch(ctx *gin.Context, rawSecret string) {
|
|||||||
candidates: candidates,
|
candidates: candidates,
|
||||||
})
|
})
|
||||||
if res.err != nil {
|
if res.err != nil {
|
||||||
writeError(ctx, http.StatusInternalServerError, res.err)
|
if errors.Is(res.err, ErrSessionNotFound) {
|
||||||
|
writeError(ctx, http.StatusNotFound, res.err)
|
||||||
|
} else {
|
||||||
|
writeError(ctx, http.StatusInternalServerError, res.err)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -254,7 +258,11 @@ func (s *httpServer) onWHIPDelete(ctx *gin.Context, rawSecret string) {
|
|||||||
secret: secret,
|
secret: secret,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeError(ctx, http.StatusInternalServerError, err)
|
if errors.Is(err, ErrSessionNotFound) {
|
||||||
|
writeError(ctx, http.StatusNotFound, err)
|
||||||
|
} else {
|
||||||
|
writeError(ctx, http.StatusInternalServerError, err)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -18,11 +18,16 @@ import (
|
|||||||
"github.com/bluenviron/mediamtx/internal/stream"
|
"github.com/bluenviron/mediamtx/internal/stream"
|
||||||
"github.com/bluenviron/mediamtx/internal/test"
|
"github.com/bluenviron/mediamtx/internal/test"
|
||||||
"github.com/bluenviron/mediamtx/internal/unit"
|
"github.com/bluenviron/mediamtx/internal/unit"
|
||||||
|
"github.com/google/uuid"
|
||||||
"github.com/pion/rtp"
|
"github.com/pion/rtp"
|
||||||
pwebrtc "github.com/pion/webrtc/v3"
|
pwebrtc "github.com/pion/webrtc/v3"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func uint16Ptr(v uint16) *uint16 {
|
||||||
|
return &v
|
||||||
|
}
|
||||||
|
|
||||||
func checkClose(t *testing.T, closeFunc func() error) {
|
func checkClose(t *testing.T, closeFunc func() error) {
|
||||||
require.NoError(t, closeFunc())
|
require.NoError(t, closeFunc())
|
||||||
}
|
}
|
||||||
@@ -90,7 +95,13 @@ func (pm *dummyPathManager) AddReader(req defs.PathAddReaderReq) (defs.Path, *st
|
|||||||
return pm.path, pm.path.stream, nil
|
return pm.path, pm.path.stream, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestServerStaticPages(t *testing.T) {
|
func initializeTestServer(t *testing.T) *Server {
|
||||||
|
path := &dummyPath{
|
||||||
|
streamCreated: make(chan struct{}),
|
||||||
|
}
|
||||||
|
|
||||||
|
pathManager := &dummyPathManager{path: path}
|
||||||
|
|
||||||
s := &Server{
|
s := &Server{
|
||||||
Address: "127.0.0.1:8886",
|
Address: "127.0.0.1:8886",
|
||||||
Encryption: false,
|
Encryption: false,
|
||||||
@@ -107,11 +118,17 @@ func TestServerStaticPages(t *testing.T) {
|
|||||||
AdditionalHosts: []string{},
|
AdditionalHosts: []string{},
|
||||||
ICEServers: []conf.WebRTCICEServer{},
|
ICEServers: []conf.WebRTCICEServer{},
|
||||||
ExternalCmdPool: nil,
|
ExternalCmdPool: nil,
|
||||||
PathManager: &dummyPathManager{},
|
PathManager: pathManager,
|
||||||
Parent: test.NilLogger{},
|
Parent: test.NilLogger{},
|
||||||
}
|
}
|
||||||
err := s.Initialize()
|
err := s.Initialize()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestServerStaticPages(t *testing.T) {
|
||||||
|
s := initializeTestServer(t)
|
||||||
defer s.Close()
|
defer s.Close()
|
||||||
|
|
||||||
tr := &http.Transport{}
|
tr := &http.Transport{}
|
||||||
@@ -132,6 +149,75 @@ func TestServerStaticPages(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestServerOptionsPreflight(t *testing.T) {
|
||||||
|
s := initializeTestServer(t)
|
||||||
|
defer s.Close()
|
||||||
|
|
||||||
|
tr := &http.Transport{}
|
||||||
|
defer tr.CloseIdleConnections()
|
||||||
|
hc := &http.Client{Transport: tr}
|
||||||
|
|
||||||
|
// preflight requests must always work, without authentication
|
||||||
|
req, err := http.NewRequest(http.MethodOptions, "http://localhost:8886/teststream/whip", nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
req.Header.Set("Access-Control-Request-Method", "OPTIONS")
|
||||||
|
|
||||||
|
res, err := hc.Do(req)
|
||||||
|
require.NoError(t, err)
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
|
require.Equal(t, http.StatusNoContent, res.StatusCode)
|
||||||
|
|
||||||
|
_, ok := res.Header["Link"]
|
||||||
|
require.Equal(t, false, ok)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestServerOptionsICEServer(t *testing.T) {
|
||||||
|
pathManager := &dummyPathManager{}
|
||||||
|
|
||||||
|
s := &Server{
|
||||||
|
Address: "127.0.0.1:8886",
|
||||||
|
Encryption: false,
|
||||||
|
ServerKey: "",
|
||||||
|
ServerCert: "",
|
||||||
|
AllowOrigin: "",
|
||||||
|
TrustedProxies: conf.IPNetworks{},
|
||||||
|
ReadTimeout: conf.StringDuration(10 * time.Second),
|
||||||
|
WriteQueueSize: 512,
|
||||||
|
LocalUDPAddress: "127.0.0.1:8887",
|
||||||
|
LocalTCPAddress: "127.0.0.1:8887",
|
||||||
|
IPsFromInterfaces: true,
|
||||||
|
IPsFromInterfacesList: []string{},
|
||||||
|
AdditionalHosts: []string{},
|
||||||
|
ICEServers: []conf.WebRTCICEServer{{
|
||||||
|
URL: "example.com",
|
||||||
|
Username: "myuser",
|
||||||
|
Password: "mypass",
|
||||||
|
}},
|
||||||
|
ExternalCmdPool: nil,
|
||||||
|
PathManager: pathManager,
|
||||||
|
Parent: test.NilLogger{},
|
||||||
|
}
|
||||||
|
err := s.Initialize()
|
||||||
|
require.NoError(t, err)
|
||||||
|
defer s.Close()
|
||||||
|
|
||||||
|
tr := &http.Transport{}
|
||||||
|
defer tr.CloseIdleConnections()
|
||||||
|
hc := &http.Client{Transport: tr}
|
||||||
|
|
||||||
|
iceServers, err := webrtc.WHIPOptionsICEServers(context.Background(), hc,
|
||||||
|
"http://myuser:mypass@localhost:8886/nonexisting/whep")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
require.Equal(t, []pwebrtc.ICEServer{{
|
||||||
|
URLs: []string{"example.com"},
|
||||||
|
Username: "myuser",
|
||||||
|
Credential: "mypass",
|
||||||
|
}}, iceServers)
|
||||||
|
}
|
||||||
|
|
||||||
func TestServerPublish(t *testing.T) {
|
func TestServerPublish(t *testing.T) {
|
||||||
path := &dummyPath{
|
path := &dummyPath{
|
||||||
streamCreated: make(chan struct{}),
|
streamCreated: make(chan struct{}),
|
||||||
@@ -166,26 +252,7 @@ func TestServerPublish(t *testing.T) {
|
|||||||
defer tr.CloseIdleConnections()
|
defer tr.CloseIdleConnections()
|
||||||
hc := &http.Client{Transport: tr}
|
hc := &http.Client{Transport: tr}
|
||||||
|
|
||||||
// preflight requests must always work, without authentication
|
su, err := url.Parse("http://myuser:mypass@localhost:8886/teststream/whip?param=value")
|
||||||
func() {
|
|
||||||
req, err := http.NewRequest(http.MethodOptions, "http://localhost:8886/teststream/whip", nil)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
req.Header.Set("Access-Control-Request-Method", "OPTIONS")
|
|
||||||
|
|
||||||
res, err := hc.Do(req)
|
|
||||||
require.NoError(t, err)
|
|
||||||
defer res.Body.Close()
|
|
||||||
|
|
||||||
require.Equal(t, http.StatusNoContent, res.StatusCode)
|
|
||||||
|
|
||||||
_, ok := res.Header["Link"]
|
|
||||||
require.Equal(t, false, ok)
|
|
||||||
}()
|
|
||||||
|
|
||||||
ur := "http://myuser:mypass@localhost:8886/teststream/whip?param=value"
|
|
||||||
|
|
||||||
su, err := url.Parse(ur)
|
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
wc := &webrtc.WHIPClient{
|
wc := &webrtc.WHIPClient{
|
||||||
@@ -291,9 +358,7 @@ func TestServerRead(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
defer s.Close()
|
defer s.Close()
|
||||||
|
|
||||||
ur := "http://myuser:mypass@localhost:8886/teststream/whep?param=value"
|
u, err := url.Parse("http://myuser:mypass@localhost:8886/teststream/whep?param=value")
|
||||||
|
|
||||||
u, err := url.Parse(ur)
|
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
tr := &http.Transport{}
|
tr := &http.Transport{}
|
||||||
@@ -357,43 +422,15 @@ func TestServerRead(t *testing.T) {
|
|||||||
}, pkt)
|
}, pkt)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestServerReadNotFound(t *testing.T) {
|
func TestServerPostNotFound(t *testing.T) {
|
||||||
pathManager := &dummyPathManager{}
|
s := initializeTestServer(t)
|
||||||
|
|
||||||
s := &Server{
|
|
||||||
Address: "127.0.0.1:8886",
|
|
||||||
Encryption: false,
|
|
||||||
ServerKey: "",
|
|
||||||
ServerCert: "",
|
|
||||||
AllowOrigin: "",
|
|
||||||
TrustedProxies: conf.IPNetworks{},
|
|
||||||
ReadTimeout: conf.StringDuration(10 * time.Second),
|
|
||||||
WriteQueueSize: 512,
|
|
||||||
LocalUDPAddress: "127.0.0.1:8887",
|
|
||||||
LocalTCPAddress: "127.0.0.1:8887",
|
|
||||||
IPsFromInterfaces: true,
|
|
||||||
IPsFromInterfacesList: []string{},
|
|
||||||
AdditionalHosts: []string{},
|
|
||||||
ICEServers: []conf.WebRTCICEServer{},
|
|
||||||
ExternalCmdPool: nil,
|
|
||||||
PathManager: pathManager,
|
|
||||||
Parent: test.NilLogger{},
|
|
||||||
}
|
|
||||||
err := s.Initialize()
|
|
||||||
require.NoError(t, err)
|
|
||||||
defer s.Close()
|
defer s.Close()
|
||||||
|
|
||||||
tr := &http.Transport{}
|
tr := &http.Transport{}
|
||||||
defer tr.CloseIdleConnections()
|
defer tr.CloseIdleConnections()
|
||||||
hc := &http.Client{Transport: tr}
|
hc := &http.Client{Transport: tr}
|
||||||
|
|
||||||
iceServers, err := webrtc.WHIPOptionsICEServers(context.Background(), hc,
|
pc, err := pwebrtc.NewPeerConnection(pwebrtc.Configuration{})
|
||||||
"http://myuser:mypass@localhost:8886/nonexisting/whep")
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
pc, err := pwebrtc.NewPeerConnection(pwebrtc.Configuration{
|
|
||||||
ICEServers: iceServers,
|
|
||||||
})
|
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
defer pc.Close() //nolint:errcheck
|
defer pc.Close() //nolint:errcheck
|
||||||
|
|
||||||
@@ -416,6 +453,62 @@ func TestServerReadNotFound(t *testing.T) {
|
|||||||
require.Equal(t, http.StatusNotFound, res.StatusCode)
|
require.Equal(t, http.StatusNotFound, res.StatusCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestServerPatchNotFound(t *testing.T) {
|
||||||
|
s := initializeTestServer(t)
|
||||||
|
defer s.Close()
|
||||||
|
|
||||||
|
tr := &http.Transport{}
|
||||||
|
defer tr.CloseIdleConnections()
|
||||||
|
hc := &http.Client{Transport: tr}
|
||||||
|
|
||||||
|
pc, err := pwebrtc.NewPeerConnection(pwebrtc.Configuration{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
defer pc.Close() //nolint:errcheck
|
||||||
|
|
||||||
|
_, err = pc.AddTransceiverFromKind(pwebrtc.RTPCodecTypeVideo)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
offer, err := pc.CreateOffer(nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
frag, err := webrtc.ICEFragmentMarshal(offer.SDP, []*pwebrtc.ICECandidateInit{{
|
||||||
|
Candidate: "mycandidate",
|
||||||
|
SDPMLineIndex: uint16Ptr(0),
|
||||||
|
}})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
req, err := http.NewRequest(http.MethodPatch,
|
||||||
|
"http://localhost:8886/nonexisting/whep/"+uuid.UUID{}.String(), bytes.NewReader(frag))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
req.Header.Set("Content-Type", "application/trickle-ice-sdpfrag")
|
||||||
|
|
||||||
|
res, err := hc.Do(req)
|
||||||
|
require.NoError(t, err)
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
|
require.Equal(t, http.StatusNotFound, res.StatusCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestServerDeleteNotFound(t *testing.T) {
|
||||||
|
s := initializeTestServer(t)
|
||||||
|
defer s.Close()
|
||||||
|
|
||||||
|
tr := &http.Transport{}
|
||||||
|
defer tr.CloseIdleConnections()
|
||||||
|
hc := &http.Client{Transport: tr}
|
||||||
|
|
||||||
|
req, err := http.NewRequest(http.MethodDelete,
|
||||||
|
"http://localhost:8886/nonexisting/whep/"+uuid.UUID{}.String(), nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
res, err := hc.Do(req)
|
||||||
|
require.NoError(t, err)
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
|
require.Equal(t, http.StatusNotFound, res.StatusCode)
|
||||||
|
}
|
||||||
|
|
||||||
func TestICEServerNoClientOnly(t *testing.T) {
|
func TestICEServerNoClientOnly(t *testing.T) {
|
||||||
s := &Server{
|
s := &Server{
|
||||||
ICEServers: []conf.WebRTCICEServer{
|
ICEServers: []conf.WebRTCICEServer{
|
||||||
|
Reference in New Issue
Block a user