mirror of
https://github.com/aler9/gortsplib
synced 2025-10-04 23:02:45 +08:00
server: fill ctx.Query correctly (#73)
This commit is contained in:
15
pkg/base/path.go
Normal file
15
pkg/base/path.go
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
package base
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// PathSplitQuery splits a path from a query.
|
||||||
|
func PathSplitQuery(pathAndQuery string) (string, string) {
|
||||||
|
i := strings.Index(pathAndQuery, "?")
|
||||||
|
if i >= 0 {
|
||||||
|
return pathAndQuery[:i], pathAndQuery[i+1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
return pathAndQuery, ""
|
||||||
|
}
|
30
pkg/base/path_test.go
Normal file
30
pkg/base/path_test.go
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
package base
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestPathSplitQuery(t *testing.T) {
|
||||||
|
for _, ca := range []struct {
|
||||||
|
a string
|
||||||
|
b string
|
||||||
|
c string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"test?a=b",
|
||||||
|
"test",
|
||||||
|
"a=b",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"test",
|
||||||
|
"test",
|
||||||
|
"",
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
b, c := PathSplitQuery(ca.a)
|
||||||
|
require.Equal(t, ca.b, b)
|
||||||
|
require.Equal(t, ca.c, c)
|
||||||
|
}
|
||||||
|
}
|
@@ -3,19 +3,8 @@ package base
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// PathSplitQuery splits a path from a query.
|
|
||||||
func PathSplitQuery(pathAndQuery string) (string, string) {
|
|
||||||
i := strings.Index(pathAndQuery, "?")
|
|
||||||
if i >= 0 {
|
|
||||||
return pathAndQuery[:i], pathAndQuery[i:]
|
|
||||||
}
|
|
||||||
|
|
||||||
return pathAndQuery, ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// URL is a RTSP URL.
|
// URL is a RTSP URL.
|
||||||
// This is basically an HTTP URL with some additional functions to handle
|
// This is basically an HTTP URL with some additional functions to handle
|
||||||
// control attributes.
|
// control attributes.
|
||||||
@@ -73,17 +62,6 @@ func (u *URL) CloneWithoutCredentials() *URL {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// RTSPPath returns the path of a RTSP URL.
|
|
||||||
func (u *URL) RTSPPath() (string, bool) {
|
|
||||||
pathAndQuery, ok := u.RTSPPathAndQuery()
|
|
||||||
if !ok {
|
|
||||||
return "", false
|
|
||||||
}
|
|
||||||
|
|
||||||
path, _ := PathSplitQuery(pathAndQuery)
|
|
||||||
return path, true
|
|
||||||
}
|
|
||||||
|
|
||||||
// RTSPPathAndQuery returns the path and query of a RTSP URL.
|
// RTSPPathAndQuery returns the path and query of a RTSP URL.
|
||||||
func (u *URL) RTSPPathAndQuery() (string, bool) {
|
func (u *URL) RTSPPathAndQuery() (string, bool) {
|
||||||
var pathAndQuery string
|
var pathAndQuery string
|
||||||
|
@@ -14,7 +14,7 @@ func mustParseURL(s string) *URL {
|
|||||||
return u
|
return u
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestURLErrors(t *testing.T) {
|
func TestURLParseErrors(t *testing.T) {
|
||||||
for _, ca := range []struct {
|
for _, ca := range []struct {
|
||||||
name string
|
name string
|
||||||
enc string
|
enc string
|
||||||
@@ -48,42 +48,6 @@ func TestURLErrors(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestURLRTSPPath(t *testing.T) {
|
|
||||||
for _, ca := range []struct {
|
|
||||||
u *URL
|
|
||||||
b string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
mustParseURL("rtsp://localhost:8554/teststream"),
|
|
||||||
"teststream",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
mustParseURL("rtsp://localhost:8554/test/stream"),
|
|
||||||
"test/stream",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
mustParseURL("rtsp://192.168.1.99:554/test?user=tmp&password=BagRep1&channel=1&stream=0.sdp"),
|
|
||||||
"test",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
mustParseURL("rtsp://192.168.1.99:554/te!st?user=tmp&password=BagRep1!&channel=1&stream=0.sdp"),
|
|
||||||
"te!st",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
mustParseURL("rtsp://192.168.1.99:554/user=tmp&password=BagRep1!&channel=1&stream=0.sdp"),
|
|
||||||
"user=tmp&password=BagRep1!&channel=1&stream=0.sdp",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
mustParseURL("rtsp://localhost:8554/teststream?query1?query2"),
|
|
||||||
"teststream",
|
|
||||||
},
|
|
||||||
} {
|
|
||||||
b, ok := ca.u.RTSPPath()
|
|
||||||
require.Equal(t, true, ok)
|
|
||||||
require.Equal(t, ca.b, b)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestURLClone(t *testing.T) {
|
func TestURLClone(t *testing.T) {
|
||||||
u := mustParseURL("rtsp://localhost:8554/test/stream")
|
u := mustParseURL("rtsp://localhost:8554/test/stream")
|
||||||
u2 := u.Clone()
|
u2 := u.Clone()
|
||||||
@@ -102,12 +66,6 @@ func TestURLClone(t *testing.T) {
|
|||||||
}, u2)
|
}, u2)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestURLErrorRTSPPath(t *testing.T) {
|
|
||||||
u := mustParseURL("rtsp://localhost:8554")
|
|
||||||
_, ok := u.RTSPPath()
|
|
||||||
require.Equal(t, false, ok)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestURLRTSPPathAndQuery(t *testing.T) {
|
func TestURLRTSPPathAndQuery(t *testing.T) {
|
||||||
for _, ca := range []struct {
|
for _, ca := range []struct {
|
||||||
u *URL
|
u *URL
|
||||||
|
@@ -286,11 +286,16 @@ func TestServerHighLevelPublishRead(t *testing.T) {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
onDescribe: func(ctx *ServerHandlerOnDescribeCtx) (*base.Response, *ServerStream, error) {
|
onDescribe: func(ctx *ServerHandlerOnDescribeCtx) (*base.Response, *ServerStream, error) {
|
||||||
if ctx.Path != "teststream" {
|
if ctx.Path != "test/stream" {
|
||||||
return &base.Response{
|
return &base.Response{
|
||||||
StatusCode: base.StatusBadRequest,
|
StatusCode: base.StatusBadRequest,
|
||||||
}, nil, fmt.Errorf("invalid path (%s)", ctx.Req.URL)
|
}, nil, fmt.Errorf("invalid path (%s)", ctx.Req.URL)
|
||||||
}
|
}
|
||||||
|
if ctx.Query != "key=val" {
|
||||||
|
return &base.Response{
|
||||||
|
StatusCode: base.StatusBadRequest,
|
||||||
|
}, nil, fmt.Errorf("invalid query (%s)", ctx.Query)
|
||||||
|
}
|
||||||
|
|
||||||
mutex.Lock()
|
mutex.Lock()
|
||||||
defer mutex.Unlock()
|
defer mutex.Unlock()
|
||||||
@@ -306,11 +311,16 @@ func TestServerHighLevelPublishRead(t *testing.T) {
|
|||||||
}, stream, nil
|
}, stream, nil
|
||||||
},
|
},
|
||||||
onAnnounce: func(ctx *ServerHandlerOnAnnounceCtx) (*base.Response, error) {
|
onAnnounce: func(ctx *ServerHandlerOnAnnounceCtx) (*base.Response, error) {
|
||||||
if ctx.Path != "teststream" {
|
if ctx.Path != "test/stream" {
|
||||||
return &base.Response{
|
return &base.Response{
|
||||||
StatusCode: base.StatusBadRequest,
|
StatusCode: base.StatusBadRequest,
|
||||||
}, fmt.Errorf("invalid path (%s)", ctx.Req.URL)
|
}, fmt.Errorf("invalid path (%s)", ctx.Req.URL)
|
||||||
}
|
}
|
||||||
|
if ctx.Query != "key=val" {
|
||||||
|
return &base.Response{
|
||||||
|
StatusCode: base.StatusBadRequest,
|
||||||
|
}, fmt.Errorf("invalid query (%s)", ctx.Query)
|
||||||
|
}
|
||||||
|
|
||||||
mutex.Lock()
|
mutex.Lock()
|
||||||
defer mutex.Unlock()
|
defer mutex.Unlock()
|
||||||
@@ -329,11 +339,16 @@ func TestServerHighLevelPublishRead(t *testing.T) {
|
|||||||
}, nil
|
}, nil
|
||||||
},
|
},
|
||||||
onSetup: func(ctx *ServerHandlerOnSetupCtx) (*base.Response, *ServerStream, error) {
|
onSetup: func(ctx *ServerHandlerOnSetupCtx) (*base.Response, *ServerStream, error) {
|
||||||
if ctx.Path != "teststream" {
|
if ctx.Path != "test/stream" {
|
||||||
return &base.Response{
|
return &base.Response{
|
||||||
StatusCode: base.StatusBadRequest,
|
StatusCode: base.StatusBadRequest,
|
||||||
}, nil, fmt.Errorf("invalid path (%s)", ctx.Req.URL)
|
}, nil, fmt.Errorf("invalid path (%s)", ctx.Req.URL)
|
||||||
}
|
}
|
||||||
|
if ctx.Query != "key=val" {
|
||||||
|
return &base.Response{
|
||||||
|
StatusCode: base.StatusBadRequest,
|
||||||
|
}, nil, fmt.Errorf("invalid query (%s)", ctx.Query)
|
||||||
|
}
|
||||||
|
|
||||||
if stream == nil {
|
if stream == nil {
|
||||||
return &base.Response{
|
return &base.Response{
|
||||||
@@ -346,22 +361,32 @@ func TestServerHighLevelPublishRead(t *testing.T) {
|
|||||||
}, stream, nil
|
}, stream, nil
|
||||||
},
|
},
|
||||||
onPlay: func(ctx *ServerHandlerOnPlayCtx) (*base.Response, error) {
|
onPlay: func(ctx *ServerHandlerOnPlayCtx) (*base.Response, error) {
|
||||||
if ctx.Path != "teststream" {
|
if ctx.Path != "test/stream" {
|
||||||
return &base.Response{
|
return &base.Response{
|
||||||
StatusCode: base.StatusBadRequest,
|
StatusCode: base.StatusBadRequest,
|
||||||
}, fmt.Errorf("invalid path (%s)", ctx.Req.URL)
|
}, fmt.Errorf("invalid path (%s)", ctx.Req.URL)
|
||||||
}
|
}
|
||||||
|
if ctx.Query != "key=val" {
|
||||||
|
return &base.Response{
|
||||||
|
StatusCode: base.StatusBadRequest,
|
||||||
|
}, fmt.Errorf("invalid query (%s)", ctx.Query)
|
||||||
|
}
|
||||||
|
|
||||||
return &base.Response{
|
return &base.Response{
|
||||||
StatusCode: base.StatusOK,
|
StatusCode: base.StatusOK,
|
||||||
}, nil
|
}, nil
|
||||||
},
|
},
|
||||||
onRecord: func(ctx *ServerHandlerOnRecordCtx) (*base.Response, error) {
|
onRecord: func(ctx *ServerHandlerOnRecordCtx) (*base.Response, error) {
|
||||||
if ctx.Path != "teststream" {
|
if ctx.Path != "test/stream" {
|
||||||
return &base.Response{
|
return &base.Response{
|
||||||
StatusCode: base.StatusBadRequest,
|
StatusCode: base.StatusBadRequest,
|
||||||
}, fmt.Errorf("invalid path (%s)", ctx.Req.URL)
|
}, fmt.Errorf("invalid path (%s)", ctx.Req.URL)
|
||||||
}
|
}
|
||||||
|
if ctx.Query != "key=val" {
|
||||||
|
return &base.Response{
|
||||||
|
StatusCode: base.StatusBadRequest,
|
||||||
|
}, fmt.Errorf("invalid query (%s)", ctx.Query)
|
||||||
|
}
|
||||||
|
|
||||||
return &base.Response{
|
return &base.Response{
|
||||||
StatusCode: base.StatusOK,
|
StatusCode: base.StatusOK,
|
||||||
@@ -415,7 +440,7 @@ func TestServerHighLevelPublishRead(t *testing.T) {
|
|||||||
"-c", "copy",
|
"-c", "copy",
|
||||||
"-f", "rtsp",
|
"-f", "rtsp",
|
||||||
"-rtsp_transport", ts,
|
"-rtsp_transport", ts,
|
||||||
proto + "://localhost:8554/teststream",
|
proto + "://localhost:8554/test/stream?key=val",
|
||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
defer cnt1.close()
|
defer cnt1.close()
|
||||||
@@ -431,7 +456,7 @@ func TestServerHighLevelPublishRead(t *testing.T) {
|
|||||||
|
|
||||||
cnt1, err := newContainer("gstreamer", "publish", []string{
|
cnt1, err := newContainer("gstreamer", "publish", []string{
|
||||||
"filesrc location=emptyvideo.mkv ! matroskademux ! video/x-h264 ! rtspclientsink " +
|
"filesrc location=emptyvideo.mkv ! matroskademux ! video/x-h264 ! rtspclientsink " +
|
||||||
"location=" + proto + "://127.0.0.1:8554/teststream protocols=" + ts +
|
"location=" + proto + "://127.0.0.1:8554/test/stream?key=val protocols=" + ts +
|
||||||
" tls-validation-flags=0 latency=0 timeout=0 rtx-time=0",
|
" tls-validation-flags=0 latency=0 timeout=0 rtx-time=0",
|
||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@@ -456,7 +481,7 @@ func TestServerHighLevelPublishRead(t *testing.T) {
|
|||||||
|
|
||||||
cnt2, err := newContainer("ffmpeg", "read", []string{
|
cnt2, err := newContainer("ffmpeg", "read", []string{
|
||||||
"-rtsp_transport", ts,
|
"-rtsp_transport", ts,
|
||||||
"-i", proto + "://localhost:8554/teststream",
|
"-i", proto + "://localhost:8554/test/stream?key=val",
|
||||||
"-vframes", "1",
|
"-vframes", "1",
|
||||||
"-f", "image2",
|
"-f", "image2",
|
||||||
"-y", "/dev/null",
|
"-y", "/dev/null",
|
||||||
@@ -477,7 +502,7 @@ func TestServerHighLevelPublishRead(t *testing.T) {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
cnt2, err := newContainer("gstreamer", "read", []string{
|
cnt2, err := newContainer("gstreamer", "read", []string{
|
||||||
"rtspsrc location=" + proto + "://127.0.0.1:8554/teststream protocols=" + ts +
|
"rtspsrc location=" + proto + "://127.0.0.1:8554/test/stream?key=val protocols=" + ts +
|
||||||
" tls-validation-flags=0 latency=0 " +
|
" tls-validation-flags=0 latency=0 " +
|
||||||
"! application/x-rtp,media=video ! decodebin ! exitafterframe ! fakesink",
|
"! application/x-rtp,media=video ! decodebin ! exitafterframe ! fakesink",
|
||||||
})
|
})
|
||||||
|
@@ -334,7 +334,7 @@ func (sc *ServerConn) handleRequest(req *base.Request) (*base.Response, error) {
|
|||||||
|
|
||||||
case base.Describe:
|
case base.Describe:
|
||||||
if h, ok := sc.s.Handler.(ServerHandlerOnDescribe); ok {
|
if h, ok := sc.s.Handler.(ServerHandlerOnDescribe); ok {
|
||||||
pathAndQuery, ok := req.URL.RTSPPath()
|
pathAndQuery, ok := req.URL.RTSPPathAndQuery()
|
||||||
if !ok {
|
if !ok {
|
||||||
return &base.Response{
|
return &base.Response{
|
||||||
StatusCode: base.StatusBadRequest,
|
StatusCode: base.StatusBadRequest,
|
||||||
@@ -431,7 +431,7 @@ func (sc *ServerConn) handleRequest(req *base.Request) (*base.Response, error) {
|
|||||||
|
|
||||||
// handle request here
|
// handle request here
|
||||||
if h, ok := sc.s.Handler.(ServerHandlerOnGetParameter); ok {
|
if h, ok := sc.s.Handler.(ServerHandlerOnGetParameter); ok {
|
||||||
pathAndQuery, ok := req.URL.RTSPPath()
|
pathAndQuery, ok := req.URL.RTSPPathAndQuery()
|
||||||
if !ok {
|
if !ok {
|
||||||
return &base.Response{
|
return &base.Response{
|
||||||
StatusCode: base.StatusBadRequest,
|
StatusCode: base.StatusBadRequest,
|
||||||
@@ -450,7 +450,7 @@ func (sc *ServerConn) handleRequest(req *base.Request) (*base.Response, error) {
|
|||||||
|
|
||||||
case base.SetParameter:
|
case base.SetParameter:
|
||||||
if h, ok := sc.s.Handler.(ServerHandlerOnSetParameter); ok {
|
if h, ok := sc.s.Handler.(ServerHandlerOnSetParameter); ok {
|
||||||
pathAndQuery, ok := req.URL.RTSPPath()
|
pathAndQuery, ok := req.URL.RTSPPathAndQuery()
|
||||||
if !ok {
|
if !ok {
|
||||||
return &base.Response{
|
return &base.Response{
|
||||||
StatusCode: base.StatusBadRequest,
|
StatusCode: base.StatusBadRequest,
|
||||||
|
@@ -422,7 +422,7 @@ func (ss *ServerSession) handleRequest(sc *ServerConn, req *base.Request) (*base
|
|||||||
}, err
|
}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
pathAndQuery, ok := req.URL.RTSPPath()
|
pathAndQuery, ok := req.URL.RTSPPathAndQuery()
|
||||||
if !ok {
|
if !ok {
|
||||||
return &base.Response{
|
return &base.Response{
|
||||||
StatusCode: base.StatusBadRequest,
|
StatusCode: base.StatusBadRequest,
|
||||||
@@ -465,7 +465,7 @@ func (ss *ServerSession) handleRequest(sc *ServerConn, req *base.Request) (*base
|
|||||||
}, fmt.Errorf("unable to generate track URL")
|
}, fmt.Errorf("unable to generate track URL")
|
||||||
}
|
}
|
||||||
|
|
||||||
trackPath, ok := trackURL.RTSPPath()
|
trackPath, ok := trackURL.RTSPPathAndQuery()
|
||||||
if !ok {
|
if !ok {
|
||||||
return &base.Response{
|
return &base.Response{
|
||||||
StatusCode: base.StatusBadRequest,
|
StatusCode: base.StatusBadRequest,
|
||||||
@@ -750,7 +750,7 @@ func (ss *ServerSession) handleRequest(sc *ServerConn, req *base.Request) (*base
|
|||||||
}, liberrors.ErrServerNoTracksSetup{}
|
}, liberrors.ErrServerNoTracksSetup{}
|
||||||
}
|
}
|
||||||
|
|
||||||
pathAndQuery, ok := req.URL.RTSPPath()
|
pathAndQuery, ok := req.URL.RTSPPathAndQuery()
|
||||||
if !ok {
|
if !ok {
|
||||||
return &base.Response{
|
return &base.Response{
|
||||||
StatusCode: base.StatusBadRequest,
|
StatusCode: base.StatusBadRequest,
|
||||||
@@ -864,7 +864,7 @@ func (ss *ServerSession) handleRequest(sc *ServerConn, req *base.Request) (*base
|
|||||||
}, liberrors.ErrServerNotAllAnnouncedTracksSetup{}
|
}, liberrors.ErrServerNotAllAnnouncedTracksSetup{}
|
||||||
}
|
}
|
||||||
|
|
||||||
pathAndQuery, ok := req.URL.RTSPPath()
|
pathAndQuery, ok := req.URL.RTSPPathAndQuery()
|
||||||
if !ok {
|
if !ok {
|
||||||
return &base.Response{
|
return &base.Response{
|
||||||
StatusCode: base.StatusBadRequest,
|
StatusCode: base.StatusBadRequest,
|
||||||
@@ -938,7 +938,7 @@ func (ss *ServerSession) handleRequest(sc *ServerConn, req *base.Request) (*base
|
|||||||
}, err
|
}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
pathAndQuery, ok := req.URL.RTSPPath()
|
pathAndQuery, ok := req.URL.RTSPPathAndQuery()
|
||||||
if !ok {
|
if !ok {
|
||||||
return &base.Response{
|
return &base.Response{
|
||||||
StatusCode: base.StatusBadRequest,
|
StatusCode: base.StatusBadRequest,
|
||||||
@@ -997,7 +997,7 @@ func (ss *ServerSession) handleRequest(sc *ServerConn, req *base.Request) (*base
|
|||||||
|
|
||||||
case base.GetParameter:
|
case base.GetParameter:
|
||||||
if h, ok := sc.s.Handler.(ServerHandlerOnGetParameter); ok {
|
if h, ok := sc.s.Handler.(ServerHandlerOnGetParameter); ok {
|
||||||
pathAndQuery, ok := req.URL.RTSPPath()
|
pathAndQuery, ok := req.URL.RTSPPathAndQuery()
|
||||||
if !ok {
|
if !ok {
|
||||||
return &base.Response{
|
return &base.Response{
|
||||||
StatusCode: base.StatusBadRequest,
|
StatusCode: base.StatusBadRequest,
|
||||||
|
Reference in New Issue
Block a user