diff --git a/base/request.go b/base/request.go index 017dc752..c212ce6a 100644 --- a/base/request.go +++ b/base/request.go @@ -121,6 +121,7 @@ func (req Request) Write(bw *bufio.Writer) error { Scheme: req.Url.Scheme, Host: req.Url.Host, Path: req.Url.Path, + RawPath: req.Url.RawPath, RawQuery: req.Url.RawQuery, } diff --git a/base/request_test.go b/base/request_test.go index 79b6d424..c1e4fec4 100644 --- a/base/request_test.go +++ b/base/request_test.go @@ -9,6 +9,14 @@ import ( "github.com/stretchr/testify/require" ) +func mustParseUrl(s string) *url.URL { + u, err := url.Parse(s) + if err != nil { + panic(err) + } + return u +} + var casesRequest = []struct { name string byts []byte @@ -23,7 +31,7 @@ var casesRequest = []struct { "\r\n"), Request{ Method: "OPTIONS", - Url: &url.URL{Scheme: "rtsp", Host: "example.com", Path: "/media.mp4"}, + Url: mustParseUrl("rtsp://example.com/media.mp4"), Header: Header{ "CSeq": HeaderValue{"1"}, "Require": HeaderValue{"implicit-play"}, @@ -34,13 +42,30 @@ var casesRequest = []struct { { "describe", []byte("DESCRIBE rtsp://example.com/media.mp4 RTSP/1.0\r\n" + + "Accept: application/sdp\r\n" + "CSeq: 2\r\n" + "\r\n"), Request{ Method: "DESCRIBE", - Url: &url.URL{Scheme: "rtsp", Host: "example.com", Path: "/media.mp4"}, + Url: mustParseUrl("rtsp://example.com/media.mp4"), Header: Header{ - "CSeq": HeaderValue{"2"}, + "Accept": HeaderValue{"application/sdp"}, + "CSeq": HeaderValue{"2"}, + }, + }, + }, + { + "describe with exclamation mark", + []byte("DESCRIBE rtsp://192.168.1.99:554/user=tmp&password=BagRep1!&channel=1&stream=0.sdp RTSP/1.0\r\n" + + "Accept: application/sdp\r\n" + + "CSeq: 3\r\n" + + "\r\n"), + Request{ + Method: "DESCRIBE", + Url: mustParseUrl("rtsp://192.168.1.99:554/user=tmp&password=BagRep1!&channel=1&stream=0.sdp"), + Header: Header{ + "Accept": HeaderValue{"application/sdp"}, + "CSeq": HeaderValue{"3"}, }, }, }, @@ -66,7 +91,7 @@ var casesRequest = []struct { "m=video 2232 RTP/AVP 31\n"), Request{ Method: "ANNOUNCE", - Url: &url.URL{Scheme: "rtsp", Host: "example.com", Path: "/media.mp4"}, + Url: mustParseUrl("rtsp://example.com/media.mp4"), Header: Header{ "CSeq": HeaderValue{"7"}, "Date": HeaderValue{"23 Jan 1997 15:35:06 GMT"}, @@ -100,7 +125,7 @@ var casesRequest = []struct { "jitter\n"), Request{ Method: "GET_PARAMETER", - Url: &url.URL{Scheme: "rtsp", Host: "example.com", Path: "/media.mp4"}, + Url: mustParseUrl("rtsp://example.com/media.mp4"), Header: Header{ "CSeq": HeaderValue{"9"}, "Content-Type": HeaderValue{"text/parameters"}, diff --git a/connclient.go b/connclient.go index b5548ce4..c1e88cc4 100644 --- a/connclient.go +++ b/connclient.go @@ -281,6 +281,7 @@ func (c *ConnClient) Do(req *base.Request) (*base.Response, error) { Scheme: req.Url.Scheme, Host: req.Url.Host, Path: req.Url.Path, + RawPath: req.Url.RawPath, RawQuery: req.Url.RawQuery, } req.Header["Authorization"] = c.auth.GenerateHeader(req.Method, u) @@ -446,6 +447,7 @@ func (c *ConnClient) urlForTrack(baseUrl *url.URL, mode TransportMode, track *Tr Host: baseUrl.Host, User: baseUrl.User, Path: newUrl.Path, + RawPath: newUrl.RawPath, RawQuery: newUrl.RawQuery, } } @@ -456,14 +458,23 @@ func (c *ConnClient) urlForTrack(baseUrl *url.URL, mode TransportMode, track *Tr Host: baseUrl.Host, User: baseUrl.User, Path: baseUrl.Path, + RawPath: baseUrl.RawPath, RawQuery: baseUrl.RawQuery, } - // insert the control attribute after the query, if present + + // insert the control at the end of the url if u.RawQuery != "" { if !strings.HasSuffix(u.RawQuery, "/") { u.RawQuery += "/" } u.RawQuery += control + + } else if u.RawPath != "" { + if !strings.HasSuffix(u.RawPath, "/") { + u.RawPath += "/" + } + u.RawPath += control + } else { if !strings.HasSuffix(u.Path, "/") { u.Path += "/" @@ -782,7 +793,8 @@ func (c *ConnClient) LoopUDP() error { Host: c.streamUrl.Host, User: c.streamUrl.User, // use the stream path, otherwise some cameras do not reply - Path: c.streamUrl.Path, + Path: c.streamUrl.Path, + RawPath: c.streamUrl.RawPath, }, SkipResponse: true, })