mirror of
https://github.com/aler9/gortsplib
synced 2025-10-05 07:06:58 +08:00
server: test invalid paths
This commit is contained in:
@@ -77,12 +77,12 @@ func (e ErrServerWrongState) Error() string {
|
|||||||
e.AllowedList, e.State)
|
e.AllowedList, e.State)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ErrServerNoPath is an error that can be returned by a server.
|
// ErrServerInvalidPath is an error that can be returned by a server.
|
||||||
type ErrServerNoPath struct{}
|
type ErrServerInvalidPath struct{}
|
||||||
|
|
||||||
// Error implements the error interface.
|
// Error implements the error interface.
|
||||||
func (e ErrServerNoPath) Error() string {
|
func (e ErrServerInvalidPath) Error() string {
|
||||||
return "RTSP path can't be retrieved"
|
return "invalid path"
|
||||||
}
|
}
|
||||||
|
|
||||||
// ErrServerContentTypeMissing is an error that can be returned by a server.
|
// ErrServerContentTypeMissing is an error that can be returned by a server.
|
||||||
|
150
server_test.go
150
server_test.go
@@ -5,10 +5,12 @@ import (
|
|||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
psdp "github.com/pion/sdp/v3"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"github.com/aler9/gortsplib/pkg/base"
|
"github.com/aler9/gortsplib/pkg/base"
|
||||||
@@ -927,6 +929,10 @@ func TestServerSessionClose(t *testing.T) {
|
|||||||
}.Write(bconn.Writer)
|
}.Write(bconn.Writer)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
res, err := readResponse(bconn.Reader)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, base.StatusOK, res.StatusCode)
|
||||||
|
|
||||||
<-sessionClosed
|
<-sessionClosed
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -975,7 +981,151 @@ func TestServerSessionAutoClose(t *testing.T) {
|
|||||||
}.Write(bconn.Writer)
|
}.Write(bconn.Writer)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
res, err := readResponse(bconn.Reader)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, base.StatusOK, res.StatusCode)
|
||||||
|
|
||||||
conn.Close()
|
conn.Close()
|
||||||
|
|
||||||
<-sessionClosed
|
<-sessionClosed
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestServerErrorInvalidPath(t *testing.T) {
|
||||||
|
for _, method := range []base.Method{
|
||||||
|
base.Describe,
|
||||||
|
base.Announce,
|
||||||
|
base.Play,
|
||||||
|
base.Record,
|
||||||
|
base.Pause,
|
||||||
|
//base.GetParameter,
|
||||||
|
//base.SetParameter,
|
||||||
|
} {
|
||||||
|
t.Run(string(method), func(t *testing.T) {
|
||||||
|
s := &Server{
|
||||||
|
Handler: &testServerHandler{
|
||||||
|
onConnClose: func(sc *ServerConn, err error) {
|
||||||
|
require.Equal(t, "invalid path", err.Error())
|
||||||
|
},
|
||||||
|
onAnnounce: func(ctx *ServerHandlerOnAnnounceCtx) (*base.Response, error) {
|
||||||
|
return &base.Response{
|
||||||
|
StatusCode: base.StatusOK,
|
||||||
|
}, nil
|
||||||
|
},
|
||||||
|
onSetup: func(ctx *ServerHandlerOnSetupCtx) (*base.Response, error) {
|
||||||
|
return &base.Response{
|
||||||
|
StatusCode: base.StatusOK,
|
||||||
|
}, nil
|
||||||
|
},
|
||||||
|
onPlay: func(ctx *ServerHandlerOnPlayCtx) (*base.Response, error) {
|
||||||
|
return &base.Response{
|
||||||
|
StatusCode: base.StatusOK,
|
||||||
|
}, nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
err := s.Start("127.0.0.1:8554")
|
||||||
|
require.NoError(t, err)
|
||||||
|
defer s.Close()
|
||||||
|
|
||||||
|
conn, err := net.Dial("tcp", "localhost:8554")
|
||||||
|
require.NoError(t, err)
|
||||||
|
defer conn.Close()
|
||||||
|
bconn := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn))
|
||||||
|
|
||||||
|
sxID := ""
|
||||||
|
|
||||||
|
if method == base.Record {
|
||||||
|
track, err := NewTrackH264(96, []byte("123456"), []byte("123456"))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
tracks := Tracks{track}
|
||||||
|
for i, t := range tracks {
|
||||||
|
t.Media.Attributes = append(t.Media.Attributes, psdp.Attribute{
|
||||||
|
Key: "control",
|
||||||
|
Value: "trackID=" + strconv.FormatInt(int64(i), 10),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
err = base.Request{
|
||||||
|
Method: base.Announce,
|
||||||
|
URL: base.MustParseURL("rtsp://localhost:8554/teststream"),
|
||||||
|
Header: base.Header{
|
||||||
|
"CSeq": base.HeaderValue{"1"},
|
||||||
|
"Content-Type": base.HeaderValue{"application/sdp"},
|
||||||
|
},
|
||||||
|
Body: tracks.Write(),
|
||||||
|
}.Write(bconn.Writer)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
res, err := readResponse(bconn.Reader)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, base.StatusOK, res.StatusCode)
|
||||||
|
sxID = res.Header["Session"][0]
|
||||||
|
}
|
||||||
|
|
||||||
|
if method == base.Play || method == base.Record || method == base.Pause {
|
||||||
|
err = base.Request{
|
||||||
|
Method: base.Setup,
|
||||||
|
URL: base.MustParseURL("rtsp://localhost:8554/teststream/trackID=0"),
|
||||||
|
Header: base.Header{
|
||||||
|
"CSeq": base.HeaderValue{"2"},
|
||||||
|
"Session": base.HeaderValue{sxID},
|
||||||
|
"Transport": headers.Transport{
|
||||||
|
Protocol: StreamProtocolTCP,
|
||||||
|
Delivery: func() *base.StreamDelivery {
|
||||||
|
v := base.StreamDeliveryUnicast
|
||||||
|
return &v
|
||||||
|
}(),
|
||||||
|
Mode: func() *headers.TransportMode {
|
||||||
|
if method == base.Play || method == base.Pause {
|
||||||
|
v := headers.TransportModePlay
|
||||||
|
return &v
|
||||||
|
}
|
||||||
|
v := headers.TransportModeRecord
|
||||||
|
return &v
|
||||||
|
}(),
|
||||||
|
InterleavedIDs: &[2]int{0, 1},
|
||||||
|
}.Write(),
|
||||||
|
},
|
||||||
|
}.Write(bconn.Writer)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
res, err := readResponse(bconn.Reader)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, base.StatusOK, res.StatusCode)
|
||||||
|
sxID = res.Header["Session"][0]
|
||||||
|
}
|
||||||
|
|
||||||
|
if method == base.Pause {
|
||||||
|
err = base.Request{
|
||||||
|
Method: base.Play,
|
||||||
|
URL: base.MustParseURL("rtsp://localhost:8554/teststream/"),
|
||||||
|
Header: base.Header{
|
||||||
|
"CSeq": base.HeaderValue{"2"},
|
||||||
|
"Session": base.HeaderValue{sxID},
|
||||||
|
},
|
||||||
|
}.Write(bconn.Writer)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
res, err := readResponse(bconn.Reader)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, base.StatusOK, res.StatusCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = base.Request{
|
||||||
|
Method: method,
|
||||||
|
URL: base.MustParseURL("rtsp://localhost:8554"),
|
||||||
|
Header: base.Header{
|
||||||
|
"CSeq": base.HeaderValue{"3"},
|
||||||
|
"Session": base.HeaderValue{sxID},
|
||||||
|
},
|
||||||
|
}.Write(bconn.Writer)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
res, err := readResponse(bconn.Reader)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, base.StatusBadRequest, res.StatusCode)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -245,14 +245,14 @@ func (sc *ServerConn) run() {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
sc.nconn.Close()
|
|
||||||
<-readDone
|
|
||||||
|
|
||||||
if sc.tcpFrameEnabled {
|
if sc.tcpFrameEnabled {
|
||||||
sc.tcpFrameWriteBuffer.Close()
|
sc.tcpFrameWriteBuffer.Close()
|
||||||
<-sc.tcpFrameBackgroundWriteDone
|
<-sc.tcpFrameBackgroundWriteDone
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sc.nconn.Close()
|
||||||
|
<-readDone
|
||||||
|
|
||||||
for _, ss := range sc.sessions {
|
for _, ss := range sc.sessions {
|
||||||
ss.connRemove <- sc
|
ss.connRemove <- sc
|
||||||
}
|
}
|
||||||
@@ -336,7 +336,7 @@ func (sc *ServerConn) handleRequest(req *base.Request) (*base.Response, error) {
|
|||||||
if !ok {
|
if !ok {
|
||||||
return &base.Response{
|
return &base.Response{
|
||||||
StatusCode: base.StatusBadRequest,
|
StatusCode: base.StatusBadRequest,
|
||||||
}, liberrors.ErrServerNoPath{}
|
}, liberrors.ErrServerInvalidPath{}
|
||||||
}
|
}
|
||||||
|
|
||||||
path, query := base.PathSplitQuery(pathAndQuery)
|
path, query := base.PathSplitQuery(pathAndQuery)
|
||||||
@@ -430,7 +430,7 @@ func (sc *ServerConn) handleRequest(req *base.Request) (*base.Response, error) {
|
|||||||
if !ok {
|
if !ok {
|
||||||
return &base.Response{
|
return &base.Response{
|
||||||
StatusCode: base.StatusBadRequest,
|
StatusCode: base.StatusBadRequest,
|
||||||
}, liberrors.ErrServerNoPath{}
|
}, liberrors.ErrServerInvalidPath{}
|
||||||
}
|
}
|
||||||
|
|
||||||
path, query := base.PathSplitQuery(pathAndQuery)
|
path, query := base.PathSplitQuery(pathAndQuery)
|
||||||
@@ -449,7 +449,7 @@ func (sc *ServerConn) handleRequest(req *base.Request) (*base.Response, error) {
|
|||||||
if !ok {
|
if !ok {
|
||||||
return &base.Response{
|
return &base.Response{
|
||||||
StatusCode: base.StatusBadRequest,
|
StatusCode: base.StatusBadRequest,
|
||||||
}, liberrors.ErrServerNoPath{}
|
}, liberrors.ErrServerInvalidPath{}
|
||||||
}
|
}
|
||||||
|
|
||||||
path, query := base.PathSplitQuery(pathAndQuery)
|
path, query := base.PathSplitQuery(pathAndQuery)
|
||||||
|
@@ -26,7 +26,7 @@ func setupGetTrackIDPathQuery(url *base.URL,
|
|||||||
|
|
||||||
pathAndQuery, ok := url.RTSPPathAndQuery()
|
pathAndQuery, ok := url.RTSPPathAndQuery()
|
||||||
if !ok {
|
if !ok {
|
||||||
return 0, "", "", liberrors.ErrServerNoPath{}
|
return 0, "", "", liberrors.ErrServerInvalidPath{}
|
||||||
}
|
}
|
||||||
|
|
||||||
if thMode == nil || *thMode == headers.TransportModePlay {
|
if thMode == nil || *thMode == headers.TransportModePlay {
|
||||||
@@ -417,6 +417,15 @@ func (ss *ServerSession) handleRequest(sc *ServerConn, req *base.Request) (*base
|
|||||||
}, err
|
}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pathAndQuery, ok := req.URL.RTSPPath()
|
||||||
|
if !ok {
|
||||||
|
return &base.Response{
|
||||||
|
StatusCode: base.StatusBadRequest,
|
||||||
|
}, liberrors.ErrServerInvalidPath{}
|
||||||
|
}
|
||||||
|
|
||||||
|
path, query := base.PathSplitQuery(pathAndQuery)
|
||||||
|
|
||||||
ct, ok := req.Header["Content-Type"]
|
ct, ok := req.Header["Content-Type"]
|
||||||
if !ok || len(ct) != 1 {
|
if !ok || len(ct) != 1 {
|
||||||
return &base.Response{
|
return &base.Response{
|
||||||
@@ -443,15 +452,6 @@ func (ss *ServerSession) handleRequest(sc *ServerConn, req *base.Request) (*base
|
|||||||
}, liberrors.ErrServerSDPNoTracksDefined{}
|
}, liberrors.ErrServerSDPNoTracksDefined{}
|
||||||
}
|
}
|
||||||
|
|
||||||
pathAndQuery, ok := req.URL.RTSPPath()
|
|
||||||
if !ok {
|
|
||||||
return &base.Response{
|
|
||||||
StatusCode: base.StatusBadRequest,
|
|
||||||
}, liberrors.ErrServerNoPath{}
|
|
||||||
}
|
|
||||||
|
|
||||||
path, query := base.PathSplitQuery(pathAndQuery)
|
|
||||||
|
|
||||||
for _, track := range tracks {
|
for _, track := range tracks {
|
||||||
trackURL, err := track.URL()
|
trackURL, err := track.URL()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -681,7 +681,7 @@ func (ss *ServerSession) handleRequest(sc *ServerConn, req *base.Request) (*base
|
|||||||
if !ok {
|
if !ok {
|
||||||
return &base.Response{
|
return &base.Response{
|
||||||
StatusCode: base.StatusBadRequest,
|
StatusCode: base.StatusBadRequest,
|
||||||
}, liberrors.ErrServerNoPath{}
|
}, liberrors.ErrServerInvalidPath{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// path can end with a slash due to Content-Base, remove it
|
// path can end with a slash due to Content-Base, remove it
|
||||||
@@ -750,7 +750,7 @@ func (ss *ServerSession) handleRequest(sc *ServerConn, req *base.Request) (*base
|
|||||||
if !ok {
|
if !ok {
|
||||||
return &base.Response{
|
return &base.Response{
|
||||||
StatusCode: base.StatusBadRequest,
|
StatusCode: base.StatusBadRequest,
|
||||||
}, liberrors.ErrServerNoPath{}
|
}, liberrors.ErrServerInvalidPath{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// path can end with a slash due to Content-Base, remove it
|
// path can end with a slash due to Content-Base, remove it
|
||||||
@@ -818,7 +818,7 @@ func (ss *ServerSession) handleRequest(sc *ServerConn, req *base.Request) (*base
|
|||||||
if !ok {
|
if !ok {
|
||||||
return &base.Response{
|
return &base.Response{
|
||||||
StatusCode: base.StatusBadRequest,
|
StatusCode: base.StatusBadRequest,
|
||||||
}, liberrors.ErrServerNoPath{}
|
}, liberrors.ErrServerInvalidPath{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// path can end with a slash due to Content-Base, remove it
|
// path can end with a slash due to Content-Base, remove it
|
||||||
@@ -875,7 +875,7 @@ func (ss *ServerSession) handleRequest(sc *ServerConn, req *base.Request) (*base
|
|||||||
if !ok {
|
if !ok {
|
||||||
return &base.Response{
|
return &base.Response{
|
||||||
StatusCode: base.StatusBadRequest,
|
StatusCode: base.StatusBadRequest,
|
||||||
}, liberrors.ErrServerNoPath{}
|
}, liberrors.ErrServerInvalidPath{}
|
||||||
}
|
}
|
||||||
|
|
||||||
path, query := base.PathSplitQuery(pathAndQuery)
|
path, query := base.PathSplitQuery(pathAndQuery)
|
||||||
|
Reference in New Issue
Block a user