rtmp: fix parseURL panic and improve playpath handling

This commit is contained in:
Dan Kortschak 2019-03-13 17:25:47 +10:30
parent 8023b0d9d7
commit 30711a54fa
2 changed files with 221 additions and 13 deletions

View File

@ -78,26 +78,34 @@ func parseURL(addr string) (protocol int32, host string, port uint16, app, playp
if !path.IsAbs(u.Path) { if !path.IsAbs(u.Path) {
return protocol, host, port, app, playpath, nil return protocol, host, port, app, playpath, nil
} }
elems := strings.SplitN(u.Path[1:], "/", 3) elems := strings.SplitN(u.Path[1:], "/", 3)
app = elems[0] app = elems[0]
if app == "" { if len(elems[len(elems)-1]) == 0 {
elems = elems[:len(elems)-1]
}
if app == "" || len(elems) < 2 {
return protocol, host, port, app, playpath, errInvalidURL return protocol, host, port, app, playpath, errInvalidURL
} }
playpath = elems[1]
if len(elems) == 3 && len(elems[2]) != 0 {
playpath = path.Join(elems[1:]...) playpath = path.Join(elems[1:]...)
switch ext := path.Ext(playpath); ext { switch ext := path.Ext(playpath); ext {
case ".f4v", ".mp4": case ".f4v", ".mp4":
playpath = "mp4:" + playpath[:len(playpath)-len(ext)] playpath = playpath[:len(playpath)-len(ext)]
if !strings.HasPrefix(playpath, "mp4:") {
playpath = "mp4:" + playpath
}
case ".mp3": case ".mp3":
playpath = "mp3:" + playpath[:len(playpath)-len(ext)] playpath = playpath[:len(playpath)-len(ext)]
if !strings.HasPrefix(playpath, "mp3:") {
playpath = "mp3:" + playpath
}
case ".flv": case ".flv":
playpath = playpath[:len(playpath)-len(ext)] playpath = playpath[:len(playpath)-len(ext)]
} }
if u.RawQuery != "" { if u.RawQuery != "" {
playpath += "?" + u.RawQuery playpath += "?" + u.RawQuery
} }
}
switch { switch {
case port != 0: case port != 0:

200
rtmp/parseurl_test.go Normal file
View File

@ -0,0 +1,200 @@
/*
NAME
parseurl_test.go
DESCRIPTION
See Readme.md
AUTHOR
Dan Kortschak <dan@ausocean.org>
LICENSE
parseurl.go is Copyright (C) 2019 the Australian Ocean Lab (AusOcean)
It is free software: you can redistribute it and/or modify them
under the terms of the GNU General Public License as published by the
Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
It is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with revid in gpl.txt. If not, see http://www.gnu.org/licenses.
*/
package rtmp
import (
"testing"
)
var parseURLTests = []struct {
url string
wantProtocol int32
wantHost string
wantPort uint16
wantApp string
wantPlaypath string
wantErr error
}{
{
url: "rtmp://addr",
wantHost: "addr",
},
{
url: "rtmp://addr/",
wantErr: errInvalidURL,
},
{
url: "rtmp://addr/live2",
wantErr: errInvalidURL,
},
{
url: "rtmp://addr/live2/",
wantErr: errInvalidURL,
},
{
url: "rtmp://addr/appname/key",
wantHost: "addr",
wantPort: 1935,
wantApp: "appname",
wantPlaypath: "key",
},
{
url: "rtmp://addr/appname/instancename",
wantHost: "addr",
wantPort: 1935,
wantApp: "appname",
wantPlaypath: "instancename",
},
{
url: "rtmp://addr/appname/instancename/",
wantHost: "addr",
wantPort: 1935,
wantApp: "appname",
wantPlaypath: "instancename",
},
{
url: "rtmp://addr/appname/mp4:path.f4v",
wantHost: "addr",
wantPort: 1935,
wantApp: "appname",
wantPlaypath: "mp4:path",
},
{
url: "rtmp://addr/appname/mp4:path.f4v?param1=value1&param2=value2",
wantHost: "addr",
wantPort: 1935,
wantApp: "appname",
wantPlaypath: "mp4:path?param1=value1&param2=value2",
},
{
url: "rtmp://addr/appname/mp4:path/to/file.f4v",
wantHost: "addr",
wantPort: 1935,
wantApp: "appname",
wantPlaypath: "mp4:path/to/file",
},
{
url: "rtmp://addr/appname/mp4:path/to/file.f4v?param1=value1&param2=value2",
wantHost: "addr",
wantPort: 1935,
wantApp: "appname",
wantPlaypath: "mp4:path/to/file?param1=value1&param2=value2",
},
{
url: "rtmp://addr/appname/path.mp4",
wantHost: "addr",
wantPort: 1935,
wantApp: "appname",
wantPlaypath: "mp4:path",
},
{
url: "rtmp://addr/appname/path.mp4?param1=value1&param2=value2",
wantHost: "addr",
wantPort: 1935,
wantApp: "appname",
wantPlaypath: "mp4:path?param1=value1&param2=value2",
},
{
url: "rtmp://addr/appname/path/to/file.mp4",
wantHost: "addr",
wantPort: 1935,
wantApp: "appname",
wantPlaypath: "mp4:path/to/file",
},
{
url: "rtmp://addr/appname/path/to/file.mp4?param1=value1&param2=value2",
wantHost: "addr",
wantPort: 1935,
wantApp: "appname",
wantPlaypath: "mp4:path/to/file?param1=value1&param2=value2",
},
{
url: "rtmp://addr/appname/path.flv",
wantHost: "addr",
wantPort: 1935,
wantApp: "appname",
wantPlaypath: "path",
},
{
url: "rtmp://addr/appname/path.flv?param1=value1&param2=value2",
wantHost: "addr",
wantPort: 1935,
wantApp: "appname",
wantPlaypath: "path?param1=value1&param2=value2",
},
{
url: "rtmp://addr/appname/path/to/file.flv",
wantHost: "addr",
wantPort: 1935,
wantApp: "appname",
wantPlaypath: "path/to/file",
},
{
url: "rtmp://addr/appname/path/to/file.flv?param1=value1&param2=value2",
wantHost: "addr",
wantPort: 1935,
wantApp: "appname",
wantPlaypath: "path/to/file?param1=value1&param2=value2",
},
}
func TestParseURL(t *testing.T) {
for _, test := range parseURLTests {
func() {
defer func() {
p := recover()
if p != nil {
t.Errorf("unexpected panic for %q: %v", test.url, p)
}
}()
protocol, host, port, app, playpath, err := parseURL(test.url)
if err != test.wantErr {
t.Errorf("unexpected error for %q: got:%v want:%v", test.url, err, test.wantErr)
return
}
if err != nil {
return
}
if protocol != test.wantProtocol {
t.Errorf("unexpected protocol for %q: got:%v want:%v", test.url, protocol, test.wantProtocol)
}
if host != test.wantHost {
t.Errorf("unexpected host for %q: got:%v want:%v", test.url, host, test.wantHost)
}
if port != test.wantPort {
t.Errorf("unexpected port for %q: got:%v want:%v", test.url, port, test.wantPort)
}
if app != test.wantApp {
t.Errorf("unexpected app for %q: got:%v want:%v", test.url, app, test.wantApp)
}
if playpath != test.wantPlaypath {
t.Errorf("unexpected playpath for %q: got:%v want:%v", test.url, playpath, test.wantPlaypath)
}
}()
}
}