forked from External/mediamtx
move RTMP tests into internal/servers/rtmp (#3035)
This commit is contained in:
parent
e5e029a7f4
commit
ad58efe47d
15 changed files with 446 additions and 618 deletions
|
|
@ -149,11 +149,11 @@ func TestAPIPathsList(t *testing.T) {
|
|||
})
|
||||
|
||||
t.Run("rtsps session", func(t *testing.T) {
|
||||
serverCertFpath, err := writeTempFile(serverCert)
|
||||
serverCertFpath, err := writeTempFile(test.TLSCertPub)
|
||||
require.NoError(t, err)
|
||||
defer os.Remove(serverCertFpath)
|
||||
|
||||
serverKeyFpath, err := writeTempFile(serverKey)
|
||||
serverKeyFpath, err := writeTempFile(test.TLSCertKey)
|
||||
require.NoError(t, err)
|
||||
defer os.Remove(serverKeyFpath)
|
||||
|
||||
|
|
@ -340,11 +340,11 @@ func TestAPIPathsGet(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestAPIProtocolListGet(t *testing.T) {
|
||||
serverCertFpath, err := writeTempFile(serverCert)
|
||||
serverCertFpath, err := writeTempFile(test.TLSCertPub)
|
||||
require.NoError(t, err)
|
||||
defer os.Remove(serverCertFpath)
|
||||
|
||||
serverKeyFpath, err := writeTempFile(serverKey)
|
||||
serverKeyFpath, err := writeTempFile(test.TLSCertKey)
|
||||
require.NoError(t, err)
|
||||
defer os.Remove(serverKeyFpath)
|
||||
|
||||
|
|
@ -813,11 +813,11 @@ func TestAPIProtocolListGet(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestAPIProtocolGetNotFound(t *testing.T) {
|
||||
serverCertFpath, err := writeTempFile(serverCert)
|
||||
serverCertFpath, err := writeTempFile(test.TLSCertPub)
|
||||
require.NoError(t, err)
|
||||
defer os.Remove(serverCertFpath)
|
||||
|
||||
serverKeyFpath, err := writeTempFile(serverKey)
|
||||
serverKeyFpath, err := writeTempFile(test.TLSCertKey)
|
||||
require.NoError(t, err)
|
||||
defer os.Remove(serverKeyFpath)
|
||||
|
||||
|
|
@ -913,11 +913,11 @@ func TestAPIProtocolGetNotFound(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestAPIProtocolKick(t *testing.T) {
|
||||
serverCertFpath, err := writeTempFile(serverCert)
|
||||
serverCertFpath, err := writeTempFile(test.TLSCertPub)
|
||||
require.NoError(t, err)
|
||||
defer os.Remove(serverCertFpath)
|
||||
|
||||
serverKeyFpath, err := writeTempFile(serverKey)
|
||||
serverKeyFpath, err := writeTempFile(test.TLSCertKey)
|
||||
require.NoError(t, err)
|
||||
defer os.Remove(serverKeyFpath)
|
||||
|
||||
|
|
@ -1060,11 +1060,11 @@ func TestAPIProtocolKick(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestAPIProtocolKickNotFound(t *testing.T) {
|
||||
serverCertFpath, err := writeTempFile(serverCert)
|
||||
serverCertFpath, err := writeTempFile(test.TLSCertPub)
|
||||
require.NoError(t, err)
|
||||
defer os.Remove(serverCertFpath)
|
||||
|
||||
serverKeyFpath, err := writeTempFile(serverKey)
|
||||
serverKeyFpath, err := writeTempFile(test.TLSCertKey)
|
||||
require.NoError(t, err)
|
||||
defer os.Remove(serverKeyFpath)
|
||||
|
||||
|
|
|
|||
|
|
@ -11,58 +11,6 @@ import (
|
|||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
var serverCert = []byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIDazCCAlOgAwIBAgIUXw1hEC3LFpTsllv7D3ARJyEq7sIwDQYJKoZIhvcNAQEL
|
||||
BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
|
||||
GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yMDEyMTMxNzQ0NThaFw0zMDEy
|
||||
MTExNzQ0NThaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw
|
||||
HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3DQEB
|
||||
AQUAA4IBDwAwggEKAoIBAQDG8DyyS51810GsGwgWr5rjJK7OE1kTTLSNEEKax8Bj
|
||||
zOyiaz8rA2JGl2VUEpi2UjDr9Cm7nd+YIEVs91IIBOb7LGqObBh1kGF3u5aZxLkv
|
||||
NJE+HrLVvUhaDobK2NU+Wibqc/EI3DfUkt1rSINvv9flwTFu1qHeuLWhoySzDKEp
|
||||
OzYxpFhwjVSokZIjT4Red3OtFz7gl2E6OAWe2qoh5CwLYVdMWtKR0Xuw3BkDPk9I
|
||||
qkQKx3fqv97LPEzhyZYjDT5WvGrgZ1WDAN3booxXF3oA1H3GHQc4m/vcLatOtb8e
|
||||
nI59gMQLEbnp08cl873bAuNuM95EZieXTHNbwUnq5iybAgMBAAGjUzBRMB0GA1Ud
|
||||
DgQWBBQBKhJh8eWu0a4au9X/2fKhkFX2vjAfBgNVHSMEGDAWgBQBKhJh8eWu0a4a
|
||||
u9X/2fKhkFX2vjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBj
|
||||
3aCW0YPKukYgVK9cwN0IbVy/D0C1UPT4nupJcy/E0iC7MXPZ9D/SZxYQoAkdptdO
|
||||
xfI+RXkpQZLdODNx9uvV+cHyZHZyjtE5ENu/i5Rer2cWI/mSLZm5lUQyx+0KZ2Yu
|
||||
tEI1bsebDK30msa8QSTn0WidW9XhFnl3gRi4wRdimcQapOWYVs7ih+nAlSvng7NI
|
||||
XpAyRs8PIEbpDDBMWnldrX4TP6EWYUi49gCp8OUDRREKX3l6Ls1vZ02F34yHIt/7
|
||||
7IV/XSKG096bhW+icKBWV0IpcEsgTzPK1J1hMxgjhzIMxGboAeUU+kidthOob6Sd
|
||||
XQxaORfgM//NzX9LhUPk
|
||||
-----END CERTIFICATE-----
|
||||
`)
|
||||
|
||||
var serverKey = []byte(`-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEogIBAAKCAQEAxvA8skudfNdBrBsIFq+a4ySuzhNZE0y0jRBCmsfAY8zsoms/
|
||||
KwNiRpdlVBKYtlIw6/Qpu53fmCBFbPdSCATm+yxqjmwYdZBhd7uWmcS5LzSRPh6y
|
||||
1b1IWg6GytjVPlom6nPxCNw31JLda0iDb7/X5cExbtah3ri1oaMkswyhKTs2MaRY
|
||||
cI1UqJGSI0+EXndzrRc+4JdhOjgFntqqIeQsC2FXTFrSkdF7sNwZAz5PSKpECsd3
|
||||
6r/eyzxM4cmWIw0+Vrxq4GdVgwDd26KMVxd6ANR9xh0HOJv73C2rTrW/HpyOfYDE
|
||||
CxG56dPHJfO92wLjbjPeRGYnl0xzW8FJ6uYsmwIDAQABAoIBACi0BKcyQ3HElSJC
|
||||
kaAao+Uvnzh4yvPg8Nwf5JDIp/uDdTMyIEWLtrLczRWrjGVZYbsVROinP5VfnPTT
|
||||
kYwkfKINj2u+gC6lsNuPnRuvHXikF8eO/mYvCTur1zZvsQnF5kp4GGwIqr+qoPUP
|
||||
bB0UMndG1PdpoMryHe+JcrvTrLHDmCeH10TqOwMsQMLHYLkowvxwJWsmTY7/Qr5S
|
||||
Wm3PPpOcW2i0uyPVuyuv4yD1368fqnqJ8QFsQp1K6QtYsNnJ71Hut1/IoxK/e6hj
|
||||
5Z+byKtHVtmcLnABuoOT7BhleJNFBksX9sh83jid4tMBgci+zXNeGmgqo2EmaWAb
|
||||
agQslkECgYEA8B1rzjOHVQx/vwSzDa4XOrpoHQRfyElrGNz9JVBvnoC7AorezBXQ
|
||||
M9WTHQIFTGMjzD8pb+YJGi3gj93VN51r0SmJRxBaBRh1ZZI9kFiFzngYev8POgD3
|
||||
ygmlS3kTHCNxCK/CJkB+/jMBgtPj5ygDpCWVcTSuWlQFphePkW7jaaECgYEA1Blz
|
||||
ulqgAyJHZaqgcbcCsI2q6m527hVr9pjzNjIVmkwu38yS9RTCgdlbEVVDnS0hoifl
|
||||
+jVMEGXjF3xjyMvL50BKbQUH+KAa+V4n1WGlnZOxX9TMny8MBjEuSX2+362vQ3BX
|
||||
4vOlX00gvoc+sY+lrzvfx/OdPCHQGVYzoKCxhLsCgYA07HcviuIAV/HsO2/vyvhp
|
||||
xF5gTu+BqNUHNOZDDDid+ge+Jre2yfQLCL8VPLXIQW3Jff53IH/PGl+NtjphuLvj
|
||||
7UDJvgvpZZuymIojP6+2c3gJ3CASC9aR3JBnUzdoE1O9s2eaoMqc4scpe+SWtZYf
|
||||
3vzSZ+cqF6zrD/Rf/M35IQKBgHTU4E6ShPm09CcoaeC5sp2WK8OevZw/6IyZi78a
|
||||
r5Oiy18zzO97U/k6xVMy6F+38ILl/2Rn31JZDVJujniY6eSkIVsUHmPxrWoXV1HO
|
||||
y++U32uuSFiXDcSLarfIsE992MEJLSAynbF1Rsgsr3gXbGiuToJRyxbIeVy7gwzD
|
||||
94TpAoGAY4/PejWQj9psZfAhyk5dRGra++gYRQ/gK1IIc1g+Dd2/BxbT/RHr05GK
|
||||
6vwrfjsoRyMWteC1SsNs/CurjfQ/jqCfHNP5XPvxgd5Ec8sRJIiV7V5RTuWJsPu1
|
||||
+3K6cnKEyg+0ekYmLertRFIY6SwWmY1fyKgTvxudMcsBY7dC4xs=
|
||||
-----END RSA PRIVATE KEY-----
|
||||
`)
|
||||
|
||||
func writeTempFile(byts []byte) (string, error) {
|
||||
tmpf, err := os.CreateTemp(os.TempDir(), "rtsp-")
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -42,11 +42,11 @@ func httpPullFile(t *testing.T, hc *http.Client, u string) []byte {
|
|||
}
|
||||
|
||||
func TestMetrics(t *testing.T) {
|
||||
serverCertFpath, err := writeTempFile(serverCert)
|
||||
serverCertFpath, err := writeTempFile(test.TLSCertPub)
|
||||
require.NoError(t, err)
|
||||
defer os.Remove(serverCertFpath)
|
||||
|
||||
serverKeyFpath, err := writeTempFile(serverKey)
|
||||
serverKeyFpath, err := writeTempFile(test.TLSCertKey)
|
||||
require.NoError(t, err)
|
||||
defer os.Remove(serverKeyFpath)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,385 +0,0 @@
|
|||
package core //nolint:dupl
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"encoding/json"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/bluenviron/gortsplib/v4/pkg/format"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/bluenviron/mediamtx/internal/protocols/rtmp"
|
||||
"github.com/bluenviron/mediamtx/internal/test"
|
||||
)
|
||||
|
||||
type testHTTPAuthenticator struct {
|
||||
*http.Server
|
||||
}
|
||||
|
||||
func newTestHTTPAuthenticator(t *testing.T, protocol string, action string) *testHTTPAuthenticator {
|
||||
firstReceived := false
|
||||
|
||||
ts := &testHTTPAuthenticator{}
|
||||
|
||||
ts.Server = &http.Server{
|
||||
Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
require.Equal(t, http.MethodPost, r.Method)
|
||||
require.Equal(t, "/auth", r.URL.Path)
|
||||
|
||||
var in struct {
|
||||
IP string `json:"ip"`
|
||||
User string `json:"user"`
|
||||
Password string `json:"password"`
|
||||
Path string `json:"path"`
|
||||
Protocol string `json:"protocol"`
|
||||
ID string `json:"id"`
|
||||
Action string `json:"action"`
|
||||
Query string `json:"query"`
|
||||
}
|
||||
err := json.NewDecoder(r.Body).Decode(&in)
|
||||
require.NoError(t, err)
|
||||
|
||||
var user string
|
||||
if action == "publish" {
|
||||
user = "testpublisher"
|
||||
} else {
|
||||
user = "testreader"
|
||||
}
|
||||
|
||||
if in.IP != "127.0.0.1" ||
|
||||
in.User != user ||
|
||||
in.Password != "testpass" ||
|
||||
in.Path != "teststream" ||
|
||||
in.Protocol != protocol ||
|
||||
(firstReceived && in.ID == "") ||
|
||||
in.Action != action ||
|
||||
(in.Query != "user=testreader&pass=testpass¶m=value" &&
|
||||
in.Query != "user=testpublisher&pass=testpass¶m=value" &&
|
||||
in.Query != "param=value") {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
firstReceived = true
|
||||
}),
|
||||
}
|
||||
|
||||
ln, err := net.Listen("tcp", "127.0.0.1:9120")
|
||||
require.NoError(t, err)
|
||||
|
||||
go ts.Server.Serve(ln)
|
||||
|
||||
return ts
|
||||
}
|
||||
|
||||
func (ts *testHTTPAuthenticator) close() {
|
||||
ts.Server.Shutdown(context.Background())
|
||||
}
|
||||
|
||||
func TestRTMPServer(t *testing.T) {
|
||||
for _, encrypt := range []string{
|
||||
"plain",
|
||||
"tls",
|
||||
} {
|
||||
for _, auth := range []string{
|
||||
"none",
|
||||
"internal",
|
||||
"external",
|
||||
} {
|
||||
t.Run("encrypt_"+encrypt+"_auth_"+auth, func(t *testing.T) {
|
||||
var port string
|
||||
var conf string
|
||||
|
||||
if encrypt == "plain" {
|
||||
port = "1935"
|
||||
|
||||
conf = "rtsp: no\n" +
|
||||
"hls: no\n"
|
||||
} else {
|
||||
port = "1936"
|
||||
|
||||
serverCertFpath, err := writeTempFile(serverCert)
|
||||
require.NoError(t, err)
|
||||
defer os.Remove(serverCertFpath)
|
||||
|
||||
serverKeyFpath, err := writeTempFile(serverKey)
|
||||
require.NoError(t, err)
|
||||
defer os.Remove(serverKeyFpath)
|
||||
|
||||
conf = "rtsp: no\n" +
|
||||
"hls: no\n" +
|
||||
"webrtc: no\n" +
|
||||
"rtmpEncryption: \"yes\"\n" +
|
||||
"rtmpServerCert: " + serverCertFpath + "\n" +
|
||||
"rtmpServerKey: " + serverKeyFpath + "\n"
|
||||
}
|
||||
|
||||
switch auth {
|
||||
case "none":
|
||||
conf += "paths:\n" +
|
||||
" all_others:\n"
|
||||
|
||||
case "internal":
|
||||
conf += "paths:\n" +
|
||||
" all_others:\n" +
|
||||
" publishUser: testpublisher\n" +
|
||||
" publishPass: testpass\n" +
|
||||
" publishIPs: [127.0.0.0/16]\n" +
|
||||
" readUser: testreader\n" +
|
||||
" readPass: testpass\n" +
|
||||
" readIPs: [127.0.0.0/16]\n"
|
||||
|
||||
case "external":
|
||||
conf += "externalAuthenticationURL: http://localhost:9120/auth\n" +
|
||||
"paths:\n" +
|
||||
" all_others:\n"
|
||||
}
|
||||
|
||||
p, ok := newInstance(conf)
|
||||
require.Equal(t, true, ok)
|
||||
defer p.Close()
|
||||
|
||||
var a *testHTTPAuthenticator
|
||||
if auth == "external" {
|
||||
a = newTestHTTPAuthenticator(t, "rtmp", "publish")
|
||||
}
|
||||
|
||||
u1, err := url.Parse("rtmp://127.0.0.1:" + port + "/teststream?user=testpublisher&pass=testpass¶m=value")
|
||||
require.NoError(t, err)
|
||||
|
||||
nconn1, err := func() (net.Conn, error) {
|
||||
if encrypt == "plain" {
|
||||
return net.Dial("tcp", u1.Host)
|
||||
}
|
||||
return tls.Dial("tcp", u1.Host, &tls.Config{InsecureSkipVerify: true})
|
||||
}()
|
||||
require.NoError(t, err)
|
||||
defer nconn1.Close()
|
||||
|
||||
conn1, err := rtmp.NewClientConn(nconn1, u1, true)
|
||||
require.NoError(t, err)
|
||||
|
||||
w, err := rtmp.NewWriter(conn1, test.FormatH264, test.FormatMPEG4Audio)
|
||||
require.NoError(t, err)
|
||||
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
|
||||
if auth == "external" {
|
||||
a.close()
|
||||
a = newTestHTTPAuthenticator(t, "rtmp", "read")
|
||||
defer a.close()
|
||||
}
|
||||
|
||||
u2, err := url.Parse("rtmp://127.0.0.1:" + port + "/teststream?user=testreader&pass=testpass¶m=value")
|
||||
require.NoError(t, err)
|
||||
|
||||
nconn2, err := func() (net.Conn, error) {
|
||||
if encrypt == "plain" {
|
||||
return net.Dial("tcp", u2.Host)
|
||||
}
|
||||
return tls.Dial("tcp", u2.Host, &tls.Config{InsecureSkipVerify: true})
|
||||
}()
|
||||
require.NoError(t, err)
|
||||
defer nconn2.Close()
|
||||
|
||||
conn2, err := rtmp.NewClientConn(nconn2, u2, false)
|
||||
require.NoError(t, err)
|
||||
|
||||
r, err := rtmp.NewReader(conn2)
|
||||
require.NoError(t, err)
|
||||
|
||||
videoTrack1, audioTrack2 := r.Tracks()
|
||||
require.Equal(t, test.FormatH264, videoTrack1)
|
||||
require.Equal(t, test.FormatMPEG4Audio, audioTrack2)
|
||||
|
||||
err = w.WriteH264(0, 0, true, [][]byte{
|
||||
{0x05, 0x02, 0x03, 0x04}, // IDR 1
|
||||
{0x05, 0x02, 0x03, 0x04}, // IDR 2
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
r.OnDataH264(func(pts time.Duration, au [][]byte) {
|
||||
require.Equal(t, [][]byte{
|
||||
test.FormatH264.SPS,
|
||||
test.FormatH264.PPS,
|
||||
{ // IDR 1
|
||||
0x05, 0x02, 0x03, 0x04,
|
||||
},
|
||||
{ // IDR 2
|
||||
0x05, 0x02, 0x03, 0x04,
|
||||
},
|
||||
}, au)
|
||||
})
|
||||
|
||||
err = r.Read()
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRTMPServerAuthFail(t *testing.T) {
|
||||
t.Run("publish", func(t *testing.T) { //nolint:dupl
|
||||
p, ok := newInstance("rtsp: no\n" +
|
||||
"hls: no\n" +
|
||||
"webrtc: no\n" +
|
||||
"paths:\n" +
|
||||
" all_others:\n" +
|
||||
" publishUser: testuser2\n" +
|
||||
" publishPass: testpass\n")
|
||||
require.Equal(t, true, ok)
|
||||
defer p.Close()
|
||||
|
||||
u1, err := url.Parse("rtmp://127.0.0.1:1935/teststream?user=testuser&pass=testpass")
|
||||
require.NoError(t, err)
|
||||
|
||||
nconn1, err := net.Dial("tcp", u1.Host)
|
||||
require.NoError(t, err)
|
||||
defer nconn1.Close()
|
||||
|
||||
conn1, err := rtmp.NewClientConn(nconn1, u1, true)
|
||||
require.NoError(t, err)
|
||||
|
||||
videoTrack := &format.H264{
|
||||
PayloadTyp: 96,
|
||||
SPS: []byte{
|
||||
0x67, 0x64, 0x00, 0x0c, 0xac, 0x3b, 0x50, 0xb0,
|
||||
0x4b, 0x42, 0x00, 0x00, 0x03, 0x00, 0x02, 0x00,
|
||||
0x00, 0x03, 0x00, 0x3d, 0x08,
|
||||
},
|
||||
PPS: []byte{
|
||||
0x68, 0xee, 0x3c, 0x80,
|
||||
},
|
||||
PacketizationMode: 1,
|
||||
}
|
||||
|
||||
_, err = rtmp.NewWriter(conn1, videoTrack, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
|
||||
u2, err := url.Parse("rtmp://127.0.0.1:1935/teststream")
|
||||
require.NoError(t, err)
|
||||
|
||||
nconn2, err := net.Dial("tcp", u2.Host)
|
||||
require.NoError(t, err)
|
||||
defer nconn2.Close()
|
||||
|
||||
conn2, err := rtmp.NewClientConn(nconn2, u2, false)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = rtmp.NewReader(conn2)
|
||||
require.EqualError(t, err, "EOF")
|
||||
})
|
||||
|
||||
t.Run("publish_external", func(t *testing.T) {
|
||||
p, ok := newInstance("externalAuthenticationURL: http://localhost:9120/auth\n" +
|
||||
"paths:\n" +
|
||||
" all_others:\n")
|
||||
require.Equal(t, true, ok)
|
||||
defer p.Close()
|
||||
|
||||
a := newTestHTTPAuthenticator(t, "rtmp", "publish")
|
||||
defer a.close()
|
||||
|
||||
u1, err := url.Parse("rtmp://127.0.0.1:1935/teststream?user=testuser1&pass=testpass")
|
||||
require.NoError(t, err)
|
||||
|
||||
nconn1, err := net.Dial("tcp", u1.Host)
|
||||
require.NoError(t, err)
|
||||
defer nconn1.Close()
|
||||
|
||||
conn1, err := rtmp.NewClientConn(nconn1, u1, true)
|
||||
require.NoError(t, err)
|
||||
|
||||
videoTrack := &format.H264{
|
||||
PayloadTyp: 96,
|
||||
SPS: []byte{
|
||||
0x67, 0x64, 0x00, 0x0c, 0xac, 0x3b, 0x50, 0xb0,
|
||||
0x4b, 0x42, 0x00, 0x00, 0x03, 0x00, 0x02, 0x00,
|
||||
0x00, 0x03, 0x00, 0x3d, 0x08,
|
||||
},
|
||||
PPS: []byte{
|
||||
0x68, 0xee, 0x3c, 0x80,
|
||||
},
|
||||
PacketizationMode: 1,
|
||||
}
|
||||
|
||||
_, err = rtmp.NewWriter(conn1, videoTrack, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
|
||||
u2, err := url.Parse("rtmp://127.0.0.1:1935/teststream")
|
||||
require.NoError(t, err)
|
||||
|
||||
nconn2, err := net.Dial("tcp", u2.Host)
|
||||
require.NoError(t, err)
|
||||
defer nconn2.Close()
|
||||
|
||||
conn2, err := rtmp.NewClientConn(nconn2, u2, false)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = rtmp.NewReader(conn2)
|
||||
require.EqualError(t, err, "EOF")
|
||||
})
|
||||
|
||||
t.Run("read", func(t *testing.T) { //nolint:dupl
|
||||
p, ok := newInstance("rtsp: no\n" +
|
||||
"hls: no\n" +
|
||||
"webrtc: no\n" +
|
||||
"paths:\n" +
|
||||
" all_others:\n" +
|
||||
" readUser: testuser2\n" +
|
||||
" readPass: testpass\n")
|
||||
require.Equal(t, true, ok)
|
||||
defer p.Close()
|
||||
|
||||
u1, err := url.Parse("rtmp://127.0.0.1:1935/teststream")
|
||||
require.NoError(t, err)
|
||||
|
||||
nconn1, err := net.Dial("tcp", u1.Host)
|
||||
require.NoError(t, err)
|
||||
defer nconn1.Close()
|
||||
|
||||
conn1, err := rtmp.NewClientConn(nconn1, u1, true)
|
||||
require.NoError(t, err)
|
||||
|
||||
videoTrack := &format.H264{
|
||||
PayloadTyp: 96,
|
||||
SPS: []byte{
|
||||
0x67, 0x64, 0x00, 0x0c, 0xac, 0x3b, 0x50, 0xb0,
|
||||
0x4b, 0x42, 0x00, 0x00, 0x03, 0x00, 0x02, 0x00,
|
||||
0x00, 0x03, 0x00, 0x3d, 0x08,
|
||||
},
|
||||
PPS: []byte{
|
||||
0x68, 0xee, 0x3c, 0x80,
|
||||
},
|
||||
PacketizationMode: 1,
|
||||
}
|
||||
|
||||
_, err = rtmp.NewWriter(conn1, videoTrack, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
|
||||
u2, err := url.Parse("rtmp://127.0.0.1:1935/teststream?user=testuser1&pass=testpass")
|
||||
require.NoError(t, err)
|
||||
|
||||
nconn2, err := net.Dial("tcp", u2.Host)
|
||||
require.NoError(t, err)
|
||||
defer nconn2.Close()
|
||||
|
||||
conn2, err := rtmp.NewClientConn(nconn2, u2, false)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = rtmp.NewReader(conn2)
|
||||
require.EqualError(t, err, "EOF")
|
||||
})
|
||||
}
|
||||
|
|
@ -1,6 +1,10 @@
|
|||
package core
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/bluenviron/gortsplib/v4"
|
||||
|
|
@ -10,6 +14,70 @@ import (
|
|||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
type testHTTPAuthenticator struct {
|
||||
*http.Server
|
||||
}
|
||||
|
||||
func newTestHTTPAuthenticator(t *testing.T, protocol string, action string) *testHTTPAuthenticator {
|
||||
firstReceived := false
|
||||
|
||||
ts := &testHTTPAuthenticator{}
|
||||
|
||||
ts.Server = &http.Server{
|
||||
Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
require.Equal(t, http.MethodPost, r.Method)
|
||||
require.Equal(t, "/auth", r.URL.Path)
|
||||
|
||||
var in struct {
|
||||
IP string `json:"ip"`
|
||||
User string `json:"user"`
|
||||
Password string `json:"password"`
|
||||
Path string `json:"path"`
|
||||
Protocol string `json:"protocol"`
|
||||
ID string `json:"id"`
|
||||
Action string `json:"action"`
|
||||
Query string `json:"query"`
|
||||
}
|
||||
err := json.NewDecoder(r.Body).Decode(&in)
|
||||
require.NoError(t, err)
|
||||
|
||||
var user string
|
||||
if action == "publish" {
|
||||
user = "testpublisher"
|
||||
} else {
|
||||
user = "testreader"
|
||||
}
|
||||
|
||||
if in.IP != "127.0.0.1" ||
|
||||
in.User != user ||
|
||||
in.Password != "testpass" ||
|
||||
in.Path != "teststream" ||
|
||||
in.Protocol != protocol ||
|
||||
(firstReceived && in.ID == "") ||
|
||||
in.Action != action ||
|
||||
(in.Query != "user=testreader&pass=testpass¶m=value" &&
|
||||
in.Query != "user=testpublisher&pass=testpass¶m=value" &&
|
||||
in.Query != "param=value") {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
firstReceived = true
|
||||
}),
|
||||
}
|
||||
|
||||
ln, err := net.Listen("tcp", "127.0.0.1:9120")
|
||||
require.NoError(t, err)
|
||||
|
||||
go ts.Server.Serve(ln)
|
||||
|
||||
return ts
|
||||
}
|
||||
|
||||
func (ts *testHTTPAuthenticator) close() {
|
||||
ts.Server.Shutdown(context.Background())
|
||||
}
|
||||
|
||||
func TestRTSPServer(t *testing.T) {
|
||||
for _, auth := range []string{
|
||||
"none",
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/bluenviron/mediamtx/internal/test"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
|
|
@ -54,11 +55,11 @@ func TestRTSPServerPublishRead(t *testing.T) {
|
|||
proto = "rtsps"
|
||||
port = "8322"
|
||||
|
||||
serverCertFpath, err := writeTempFile(serverCert)
|
||||
serverCertFpath, err := writeTempFile(test.TLSCertPub)
|
||||
require.NoError(t, err)
|
||||
defer os.Remove(serverCertFpath)
|
||||
|
||||
serverKeyFpath, err := writeTempFile(serverKey)
|
||||
serverKeyFpath, err := writeTempFile(test.TLSCertKey)
|
||||
require.NoError(t, err)
|
||||
defer os.Remove(serverKeyFpath)
|
||||
|
||||
|
|
|
|||
|
|
@ -12,58 +12,6 @@ import (
|
|||
"github.com/bluenviron/mediamtx/internal/core"
|
||||
)
|
||||
|
||||
var serverCert = []byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIDazCCAlOgAwIBAgIUXw1hEC3LFpTsllv7D3ARJyEq7sIwDQYJKoZIhvcNAQEL
|
||||
BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
|
||||
GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yMDEyMTMxNzQ0NThaFw0zMDEy
|
||||
MTExNzQ0NThaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw
|
||||
HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3DQEB
|
||||
AQUAA4IBDwAwggEKAoIBAQDG8DyyS51810GsGwgWr5rjJK7OE1kTTLSNEEKax8Bj
|
||||
zOyiaz8rA2JGl2VUEpi2UjDr9Cm7nd+YIEVs91IIBOb7LGqObBh1kGF3u5aZxLkv
|
||||
NJE+HrLVvUhaDobK2NU+Wibqc/EI3DfUkt1rSINvv9flwTFu1qHeuLWhoySzDKEp
|
||||
OzYxpFhwjVSokZIjT4Red3OtFz7gl2E6OAWe2qoh5CwLYVdMWtKR0Xuw3BkDPk9I
|
||||
qkQKx3fqv97LPEzhyZYjDT5WvGrgZ1WDAN3booxXF3oA1H3GHQc4m/vcLatOtb8e
|
||||
nI59gMQLEbnp08cl873bAuNuM95EZieXTHNbwUnq5iybAgMBAAGjUzBRMB0GA1Ud
|
||||
DgQWBBQBKhJh8eWu0a4au9X/2fKhkFX2vjAfBgNVHSMEGDAWgBQBKhJh8eWu0a4a
|
||||
u9X/2fKhkFX2vjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBj
|
||||
3aCW0YPKukYgVK9cwN0IbVy/D0C1UPT4nupJcy/E0iC7MXPZ9D/SZxYQoAkdptdO
|
||||
xfI+RXkpQZLdODNx9uvV+cHyZHZyjtE5ENu/i5Rer2cWI/mSLZm5lUQyx+0KZ2Yu
|
||||
tEI1bsebDK30msa8QSTn0WidW9XhFnl3gRi4wRdimcQapOWYVs7ih+nAlSvng7NI
|
||||
XpAyRs8PIEbpDDBMWnldrX4TP6EWYUi49gCp8OUDRREKX3l6Ls1vZ02F34yHIt/7
|
||||
7IV/XSKG096bhW+icKBWV0IpcEsgTzPK1J1hMxgjhzIMxGboAeUU+kidthOob6Sd
|
||||
XQxaORfgM//NzX9LhUPk
|
||||
-----END CERTIFICATE-----
|
||||
`)
|
||||
|
||||
var serverKey = []byte(`-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEogIBAAKCAQEAxvA8skudfNdBrBsIFq+a4ySuzhNZE0y0jRBCmsfAY8zsoms/
|
||||
KwNiRpdlVBKYtlIw6/Qpu53fmCBFbPdSCATm+yxqjmwYdZBhd7uWmcS5LzSRPh6y
|
||||
1b1IWg6GytjVPlom6nPxCNw31JLda0iDb7/X5cExbtah3ri1oaMkswyhKTs2MaRY
|
||||
cI1UqJGSI0+EXndzrRc+4JdhOjgFntqqIeQsC2FXTFrSkdF7sNwZAz5PSKpECsd3
|
||||
6r/eyzxM4cmWIw0+Vrxq4GdVgwDd26KMVxd6ANR9xh0HOJv73C2rTrW/HpyOfYDE
|
||||
CxG56dPHJfO92wLjbjPeRGYnl0xzW8FJ6uYsmwIDAQABAoIBACi0BKcyQ3HElSJC
|
||||
kaAao+Uvnzh4yvPg8Nwf5JDIp/uDdTMyIEWLtrLczRWrjGVZYbsVROinP5VfnPTT
|
||||
kYwkfKINj2u+gC6lsNuPnRuvHXikF8eO/mYvCTur1zZvsQnF5kp4GGwIqr+qoPUP
|
||||
bB0UMndG1PdpoMryHe+JcrvTrLHDmCeH10TqOwMsQMLHYLkowvxwJWsmTY7/Qr5S
|
||||
Wm3PPpOcW2i0uyPVuyuv4yD1368fqnqJ8QFsQp1K6QtYsNnJ71Hut1/IoxK/e6hj
|
||||
5Z+byKtHVtmcLnABuoOT7BhleJNFBksX9sh83jid4tMBgci+zXNeGmgqo2EmaWAb
|
||||
agQslkECgYEA8B1rzjOHVQx/vwSzDa4XOrpoHQRfyElrGNz9JVBvnoC7AorezBXQ
|
||||
M9WTHQIFTGMjzD8pb+YJGi3gj93VN51r0SmJRxBaBRh1ZZI9kFiFzngYev8POgD3
|
||||
ygmlS3kTHCNxCK/CJkB+/jMBgtPj5ygDpCWVcTSuWlQFphePkW7jaaECgYEA1Blz
|
||||
ulqgAyJHZaqgcbcCsI2q6m527hVr9pjzNjIVmkwu38yS9RTCgdlbEVVDnS0hoifl
|
||||
+jVMEGXjF3xjyMvL50BKbQUH+KAa+V4n1WGlnZOxX9TMny8MBjEuSX2+362vQ3BX
|
||||
4vOlX00gvoc+sY+lrzvfx/OdPCHQGVYzoKCxhLsCgYA07HcviuIAV/HsO2/vyvhp
|
||||
xF5gTu+BqNUHNOZDDDid+ge+Jre2yfQLCL8VPLXIQW3Jff53IH/PGl+NtjphuLvj
|
||||
7UDJvgvpZZuymIojP6+2c3gJ3CASC9aR3JBnUzdoE1O9s2eaoMqc4scpe+SWtZYf
|
||||
3vzSZ+cqF6zrD/Rf/M35IQKBgHTU4E6ShPm09CcoaeC5sp2WK8OevZw/6IyZi78a
|
||||
r5Oiy18zzO97U/k6xVMy6F+38ILl/2Rn31JZDVJujniY6eSkIVsUHmPxrWoXV1HO
|
||||
y++U32uuSFiXDcSLarfIsE992MEJLSAynbF1Rsgsr3gXbGiuToJRyxbIeVy7gwzD
|
||||
94TpAoGAY4/PejWQj9psZfAhyk5dRGra++gYRQ/gK1IIc1g+Dd2/BxbT/RHr05GK
|
||||
6vwrfjsoRyMWteC1SsNs/CurjfQ/jqCfHNP5XPvxgd5Ec8sRJIiV7V5RTuWJsPu1
|
||||
+3K6cnKEyg+0ekYmLertRFIY6SwWmY1fyKgTvxudMcsBY7dC4xs=
|
||||
-----END RSA PRIVATE KEY-----
|
||||
`)
|
||||
|
||||
func writeTempFile(byts []byte) (string, error) {
|
||||
tmpf, err := os.CreateTemp(os.TempDir(), "rtsp-")
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ type conn struct {
|
|||
wg *sync.WaitGroup
|
||||
nconn net.Conn
|
||||
externalCmdPool *externalcmd.Pool
|
||||
pathManager defs.PathManager
|
||||
pathManager serverPathManager
|
||||
parent *Server
|
||||
|
||||
ctx context.Context
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import (
|
|||
"github.com/bluenviron/mediamtx/internal/externalcmd"
|
||||
"github.com/bluenviron/mediamtx/internal/logger"
|
||||
"github.com/bluenviron/mediamtx/internal/restrictnetwork"
|
||||
"github.com/bluenviron/mediamtx/internal/stream"
|
||||
)
|
||||
|
||||
// ErrConnNotFound is returned when a connection is not found.
|
||||
|
|
@ -50,6 +51,11 @@ type serverAPIConnsKickReq struct {
|
|||
res chan serverAPIConnsKickRes
|
||||
}
|
||||
|
||||
type serverPathManager interface {
|
||||
AddPublisher(req defs.PathAddPublisherReq) (defs.Path, error)
|
||||
AddReader(req defs.PathAddReaderReq) (defs.Path, *stream.Stream, error)
|
||||
}
|
||||
|
||||
type serverParent interface {
|
||||
logger.Writer
|
||||
}
|
||||
|
|
@ -68,7 +74,7 @@ type Server struct {
|
|||
RunOnConnectRestart bool
|
||||
RunOnDisconnect string
|
||||
ExternalCmdPool *externalcmd.Pool
|
||||
PathManager defs.PathManager
|
||||
PathManager serverPathManager
|
||||
Parent serverParent
|
||||
|
||||
ctx context.Context
|
||||
|
|
|
|||
290
internal/servers/rtmp/server_test.go
Normal file
290
internal/servers/rtmp/server_test.go
Normal file
|
|
@ -0,0 +1,290 @@
|
|||
package rtmp
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"net"
|
||||
"net/url"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/bluenviron/gortsplib/v4/pkg/description"
|
||||
"github.com/bluenviron/gortsplib/v4/pkg/format"
|
||||
"github.com/bluenviron/mediamtx/internal/asyncwriter"
|
||||
"github.com/bluenviron/mediamtx/internal/conf"
|
||||
"github.com/bluenviron/mediamtx/internal/defs"
|
||||
"github.com/bluenviron/mediamtx/internal/externalcmd"
|
||||
"github.com/bluenviron/mediamtx/internal/protocols/rtmp"
|
||||
"github.com/bluenviron/mediamtx/internal/stream"
|
||||
"github.com/bluenviron/mediamtx/internal/test"
|
||||
"github.com/bluenviron/mediamtx/internal/unit"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func writeTempFile(byts []byte) (string, error) {
|
||||
tmpf, err := os.CreateTemp(os.TempDir(), "rtsp-")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer tmpf.Close()
|
||||
|
||||
_, err = tmpf.Write(byts)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return tmpf.Name(), nil
|
||||
}
|
||||
|
||||
type dummyPath struct {
|
||||
stream *stream.Stream
|
||||
streamCreated chan struct{}
|
||||
}
|
||||
|
||||
func (p *dummyPath) Name() string {
|
||||
return "teststream"
|
||||
}
|
||||
|
||||
func (p *dummyPath) SafeConf() *conf.Path {
|
||||
return &conf.Path{}
|
||||
}
|
||||
|
||||
func (p *dummyPath) ExternalCmdEnv() externalcmd.Environment {
|
||||
return externalcmd.Environment{}
|
||||
}
|
||||
|
||||
func (p *dummyPath) StartPublisher(req defs.PathStartPublisherReq) (*stream.Stream, error) {
|
||||
var err error
|
||||
p.stream, err = stream.New(
|
||||
1460,
|
||||
req.Desc,
|
||||
true,
|
||||
test.NilLogger{},
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
close(p.streamCreated)
|
||||
return p.stream, nil
|
||||
}
|
||||
|
||||
func (p *dummyPath) StopPublisher(_ defs.PathStopPublisherReq) {
|
||||
}
|
||||
|
||||
func (p *dummyPath) RemovePublisher(_ defs.PathRemovePublisherReq) {
|
||||
}
|
||||
|
||||
func (p *dummyPath) RemoveReader(_ defs.PathRemoveReaderReq) {
|
||||
}
|
||||
|
||||
type dummyPathManager struct {
|
||||
path *dummyPath
|
||||
}
|
||||
|
||||
func (pm *dummyPathManager) AddPublisher(_ defs.PathAddPublisherReq) (defs.Path, error) {
|
||||
return pm.path, nil
|
||||
}
|
||||
|
||||
func (pm *dummyPathManager) AddReader(_ defs.PathAddReaderReq) (defs.Path, *stream.Stream, error) {
|
||||
return pm.path, pm.path.stream, nil
|
||||
}
|
||||
|
||||
func TestServerPublish(t *testing.T) {
|
||||
for _, encrypt := range []string{
|
||||
"plain",
|
||||
"tls",
|
||||
} {
|
||||
t.Run(encrypt, func(t *testing.T) {
|
||||
var serverCertFpath string
|
||||
var serverKeyFpath string
|
||||
|
||||
if encrypt == "tls" {
|
||||
var err error
|
||||
serverCertFpath, err = writeTempFile(test.TLSCertPub)
|
||||
require.NoError(t, err)
|
||||
defer os.Remove(serverCertFpath)
|
||||
|
||||
serverKeyFpath, err = writeTempFile(test.TLSCertKey)
|
||||
require.NoError(t, err)
|
||||
defer os.Remove(serverKeyFpath)
|
||||
}
|
||||
|
||||
path := &dummyPath{
|
||||
streamCreated: make(chan struct{}),
|
||||
}
|
||||
|
||||
pathManager := &dummyPathManager{path: path}
|
||||
|
||||
s := &Server{
|
||||
Address: "127.0.0.1:1935",
|
||||
ReadTimeout: conf.StringDuration(10 * time.Second),
|
||||
WriteTimeout: conf.StringDuration(10 * time.Second),
|
||||
WriteQueueSize: 512,
|
||||
IsTLS: encrypt == "tls",
|
||||
ServerCert: serverCertFpath,
|
||||
ServerKey: serverKeyFpath,
|
||||
RTSPAddress: "",
|
||||
RunOnConnect: "",
|
||||
RunOnConnectRestart: false,
|
||||
RunOnDisconnect: "",
|
||||
ExternalCmdPool: nil,
|
||||
PathManager: pathManager,
|
||||
Parent: &test.NilLogger{},
|
||||
}
|
||||
err := s.Initialize()
|
||||
require.NoError(t, err)
|
||||
defer s.Close()
|
||||
|
||||
u, err := url.Parse("rtmp://127.0.0.1:1935/teststream?user=testpublisher&pass=testpass¶m=value")
|
||||
require.NoError(t, err)
|
||||
|
||||
nconn, err := func() (net.Conn, error) {
|
||||
if encrypt == "plain" {
|
||||
return net.Dial("tcp", u.Host)
|
||||
}
|
||||
return tls.Dial("tcp", u.Host, &tls.Config{InsecureSkipVerify: true})
|
||||
}()
|
||||
require.NoError(t, err)
|
||||
defer nconn.Close()
|
||||
|
||||
conn, err := rtmp.NewClientConn(nconn, u, true)
|
||||
require.NoError(t, err)
|
||||
|
||||
w, err := rtmp.NewWriter(conn, test.FormatH264, test.FormatMPEG4Audio)
|
||||
require.NoError(t, err)
|
||||
|
||||
<-path.streamCreated
|
||||
|
||||
aw := asyncwriter.New(512, &test.NilLogger{})
|
||||
|
||||
recv := make(chan struct{})
|
||||
|
||||
path.stream.AddReader(aw,
|
||||
path.stream.Desc().Medias[0],
|
||||
path.stream.Desc().Medias[0].Formats[0],
|
||||
func(u unit.Unit) error {
|
||||
require.Equal(t, [][]byte{
|
||||
test.FormatH264.SPS,
|
||||
test.FormatH264.PPS,
|
||||
{5, 2, 3, 4},
|
||||
}, u.(*unit.H264).AU)
|
||||
close(recv)
|
||||
return nil
|
||||
})
|
||||
|
||||
err = w.WriteH264(0, 0, true, [][]byte{
|
||||
{5, 2, 3, 4},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
aw.Start()
|
||||
|
||||
<-recv
|
||||
|
||||
aw.Stop()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestServerRead(t *testing.T) {
|
||||
for _, encrypt := range []string{
|
||||
"plain",
|
||||
"tls",
|
||||
} {
|
||||
t.Run(encrypt, func(t *testing.T) {
|
||||
var serverCertFpath string
|
||||
var serverKeyFpath string
|
||||
|
||||
if encrypt == "tls" {
|
||||
var err error
|
||||
serverCertFpath, err = writeTempFile(test.TLSCertPub)
|
||||
require.NoError(t, err)
|
||||
defer os.Remove(serverCertFpath)
|
||||
|
||||
serverKeyFpath, err = writeTempFile(test.TLSCertKey)
|
||||
require.NoError(t, err)
|
||||
defer os.Remove(serverKeyFpath)
|
||||
}
|
||||
|
||||
testMediaH264 := &description.Media{
|
||||
Type: description.MediaTypeVideo,
|
||||
Formats: []format.Format{test.FormatH264},
|
||||
}
|
||||
|
||||
desc := &description.Session{Medias: []*description.Media{testMediaH264}}
|
||||
|
||||
stream, err := stream.New(
|
||||
1460,
|
||||
desc,
|
||||
true,
|
||||
test.NilLogger{},
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
path := &dummyPath{stream: stream}
|
||||
|
||||
pathManager := &dummyPathManager{path: path}
|
||||
|
||||
s := &Server{
|
||||
Address: "127.0.0.1:1935",
|
||||
ReadTimeout: conf.StringDuration(10 * time.Second),
|
||||
WriteTimeout: conf.StringDuration(10 * time.Second),
|
||||
WriteQueueSize: 512,
|
||||
IsTLS: encrypt == "tls",
|
||||
ServerCert: serverCertFpath,
|
||||
ServerKey: serverKeyFpath,
|
||||
RTSPAddress: "",
|
||||
RunOnConnect: "",
|
||||
RunOnConnectRestart: false,
|
||||
RunOnDisconnect: "",
|
||||
ExternalCmdPool: nil,
|
||||
PathManager: pathManager,
|
||||
Parent: &test.NilLogger{},
|
||||
}
|
||||
err = s.Initialize()
|
||||
require.NoError(t, err)
|
||||
defer s.Close()
|
||||
|
||||
u, err := url.Parse("rtmp://127.0.0.1:1935/teststream?user=testreader&pass=testpass¶m=value")
|
||||
require.NoError(t, err)
|
||||
|
||||
nconn, err := func() (net.Conn, error) {
|
||||
if encrypt == "plain" {
|
||||
return net.Dial("tcp", u.Host)
|
||||
}
|
||||
return tls.Dial("tcp", u.Host, &tls.Config{InsecureSkipVerify: true})
|
||||
}()
|
||||
require.NoError(t, err)
|
||||
defer nconn.Close()
|
||||
|
||||
conn, err := rtmp.NewClientConn(nconn, u, false)
|
||||
require.NoError(t, err)
|
||||
|
||||
r, err := rtmp.NewReader(conn)
|
||||
require.NoError(t, err)
|
||||
|
||||
videoTrack, _ := r.Tracks()
|
||||
require.Equal(t, test.FormatH264, videoTrack)
|
||||
|
||||
stream.WriteUnit(desc.Medias[0], desc.Medias[0].Formats[0], &unit.H264{
|
||||
Base: unit.Base{
|
||||
NTP: time.Time{},
|
||||
},
|
||||
AU: [][]byte{
|
||||
{5, 2, 3, 4}, // IDR
|
||||
},
|
||||
})
|
||||
|
||||
r.OnDataH264(func(pts time.Duration, au [][]byte) {
|
||||
require.Equal(t, [][]byte{
|
||||
test.FormatH264.SPS,
|
||||
test.FormatH264.PPS,
|
||||
{5, 2, 3, 4},
|
||||
}, au)
|
||||
})
|
||||
|
||||
err = r.Read()
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -15,58 +15,6 @@ import (
|
|||
"github.com/bluenviron/mediamtx/internal/test"
|
||||
)
|
||||
|
||||
var serverCert = []byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIDazCCAlOgAwIBAgIUXw1hEC3LFpTsllv7D3ARJyEq7sIwDQYJKoZIhvcNAQEL
|
||||
BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
|
||||
GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yMDEyMTMxNzQ0NThaFw0zMDEy
|
||||
MTExNzQ0NThaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw
|
||||
HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3DQEB
|
||||
AQUAA4IBDwAwggEKAoIBAQDG8DyyS51810GsGwgWr5rjJK7OE1kTTLSNEEKax8Bj
|
||||
zOyiaz8rA2JGl2VUEpi2UjDr9Cm7nd+YIEVs91IIBOb7LGqObBh1kGF3u5aZxLkv
|
||||
NJE+HrLVvUhaDobK2NU+Wibqc/EI3DfUkt1rSINvv9flwTFu1qHeuLWhoySzDKEp
|
||||
OzYxpFhwjVSokZIjT4Red3OtFz7gl2E6OAWe2qoh5CwLYVdMWtKR0Xuw3BkDPk9I
|
||||
qkQKx3fqv97LPEzhyZYjDT5WvGrgZ1WDAN3booxXF3oA1H3GHQc4m/vcLatOtb8e
|
||||
nI59gMQLEbnp08cl873bAuNuM95EZieXTHNbwUnq5iybAgMBAAGjUzBRMB0GA1Ud
|
||||
DgQWBBQBKhJh8eWu0a4au9X/2fKhkFX2vjAfBgNVHSMEGDAWgBQBKhJh8eWu0a4a
|
||||
u9X/2fKhkFX2vjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBj
|
||||
3aCW0YPKukYgVK9cwN0IbVy/D0C1UPT4nupJcy/E0iC7MXPZ9D/SZxYQoAkdptdO
|
||||
xfI+RXkpQZLdODNx9uvV+cHyZHZyjtE5ENu/i5Rer2cWI/mSLZm5lUQyx+0KZ2Yu
|
||||
tEI1bsebDK30msa8QSTn0WidW9XhFnl3gRi4wRdimcQapOWYVs7ih+nAlSvng7NI
|
||||
XpAyRs8PIEbpDDBMWnldrX4TP6EWYUi49gCp8OUDRREKX3l6Ls1vZ02F34yHIt/7
|
||||
7IV/XSKG096bhW+icKBWV0IpcEsgTzPK1J1hMxgjhzIMxGboAeUU+kidthOob6Sd
|
||||
XQxaORfgM//NzX9LhUPk
|
||||
-----END CERTIFICATE-----
|
||||
`)
|
||||
|
||||
var serverKey = []byte(`-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEogIBAAKCAQEAxvA8skudfNdBrBsIFq+a4ySuzhNZE0y0jRBCmsfAY8zsoms/
|
||||
KwNiRpdlVBKYtlIw6/Qpu53fmCBFbPdSCATm+yxqjmwYdZBhd7uWmcS5LzSRPh6y
|
||||
1b1IWg6GytjVPlom6nPxCNw31JLda0iDb7/X5cExbtah3ri1oaMkswyhKTs2MaRY
|
||||
cI1UqJGSI0+EXndzrRc+4JdhOjgFntqqIeQsC2FXTFrSkdF7sNwZAz5PSKpECsd3
|
||||
6r/eyzxM4cmWIw0+Vrxq4GdVgwDd26KMVxd6ANR9xh0HOJv73C2rTrW/HpyOfYDE
|
||||
CxG56dPHJfO92wLjbjPeRGYnl0xzW8FJ6uYsmwIDAQABAoIBACi0BKcyQ3HElSJC
|
||||
kaAao+Uvnzh4yvPg8Nwf5JDIp/uDdTMyIEWLtrLczRWrjGVZYbsVROinP5VfnPTT
|
||||
kYwkfKINj2u+gC6lsNuPnRuvHXikF8eO/mYvCTur1zZvsQnF5kp4GGwIqr+qoPUP
|
||||
bB0UMndG1PdpoMryHe+JcrvTrLHDmCeH10TqOwMsQMLHYLkowvxwJWsmTY7/Qr5S
|
||||
Wm3PPpOcW2i0uyPVuyuv4yD1368fqnqJ8QFsQp1K6QtYsNnJ71Hut1/IoxK/e6hj
|
||||
5Z+byKtHVtmcLnABuoOT7BhleJNFBksX9sh83jid4tMBgci+zXNeGmgqo2EmaWAb
|
||||
agQslkECgYEA8B1rzjOHVQx/vwSzDa4XOrpoHQRfyElrGNz9JVBvnoC7AorezBXQ
|
||||
M9WTHQIFTGMjzD8pb+YJGi3gj93VN51r0SmJRxBaBRh1ZZI9kFiFzngYev8POgD3
|
||||
ygmlS3kTHCNxCK/CJkB+/jMBgtPj5ygDpCWVcTSuWlQFphePkW7jaaECgYEA1Blz
|
||||
ulqgAyJHZaqgcbcCsI2q6m527hVr9pjzNjIVmkwu38yS9RTCgdlbEVVDnS0hoifl
|
||||
+jVMEGXjF3xjyMvL50BKbQUH+KAa+V4n1WGlnZOxX9TMny8MBjEuSX2+362vQ3BX
|
||||
4vOlX00gvoc+sY+lrzvfx/OdPCHQGVYzoKCxhLsCgYA07HcviuIAV/HsO2/vyvhp
|
||||
xF5gTu+BqNUHNOZDDDid+ge+Jre2yfQLCL8VPLXIQW3Jff53IH/PGl+NtjphuLvj
|
||||
7UDJvgvpZZuymIojP6+2c3gJ3CASC9aR3JBnUzdoE1O9s2eaoMqc4scpe+SWtZYf
|
||||
3vzSZ+cqF6zrD/Rf/M35IQKBgHTU4E6ShPm09CcoaeC5sp2WK8OevZw/6IyZi78a
|
||||
r5Oiy18zzO97U/k6xVMy6F+38ILl/2Rn31JZDVJujniY6eSkIVsUHmPxrWoXV1HO
|
||||
y++U32uuSFiXDcSLarfIsE992MEJLSAynbF1Rsgsr3gXbGiuToJRyxbIeVy7gwzD
|
||||
94TpAoGAY4/PejWQj9psZfAhyk5dRGra++gYRQ/gK1IIc1g+Dd2/BxbT/RHr05GK
|
||||
6vwrfjsoRyMWteC1SsNs/CurjfQ/jqCfHNP5XPvxgd5Ec8sRJIiV7V5RTuWJsPu1
|
||||
+3K6cnKEyg+0ekYmLertRFIY6SwWmY1fyKgTvxudMcsBY7dC4xs=
|
||||
-----END RSA PRIVATE KEY-----
|
||||
`)
|
||||
|
||||
func writeTempFile(byts []byte) (string, error) {
|
||||
tmpf, err := os.CreateTemp(os.TempDir(), "rtsp-")
|
||||
if err != nil {
|
||||
|
|
@ -93,11 +41,11 @@ func TestSource(t *testing.T) {
|
|||
return net.Listen("tcp", "127.0.0.1:1935")
|
||||
}
|
||||
|
||||
serverCertFpath, err := writeTempFile(serverCert)
|
||||
serverCertFpath, err := writeTempFile(test.TLSCertPub)
|
||||
require.NoError(t, err)
|
||||
defer os.Remove(serverCertFpath)
|
||||
|
||||
serverKeyFpath, err := writeTempFile(serverKey)
|
||||
serverKeyFpath, err := writeTempFile(test.TLSCertKey)
|
||||
require.NoError(t, err)
|
||||
defer os.Remove(serverKeyFpath)
|
||||
|
||||
|
|
|
|||
|
|
@ -19,58 +19,6 @@ import (
|
|||
"github.com/bluenviron/mediamtx/internal/test"
|
||||
)
|
||||
|
||||
var serverCert = []byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIDazCCAlOgAwIBAgIUXw1hEC3LFpTsllv7D3ARJyEq7sIwDQYJKoZIhvcNAQEL
|
||||
BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
|
||||
GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yMDEyMTMxNzQ0NThaFw0zMDEy
|
||||
MTExNzQ0NThaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw
|
||||
HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3DQEB
|
||||
AQUAA4IBDwAwggEKAoIBAQDG8DyyS51810GsGwgWr5rjJK7OE1kTTLSNEEKax8Bj
|
||||
zOyiaz8rA2JGl2VUEpi2UjDr9Cm7nd+YIEVs91IIBOb7LGqObBh1kGF3u5aZxLkv
|
||||
NJE+HrLVvUhaDobK2NU+Wibqc/EI3DfUkt1rSINvv9flwTFu1qHeuLWhoySzDKEp
|
||||
OzYxpFhwjVSokZIjT4Red3OtFz7gl2E6OAWe2qoh5CwLYVdMWtKR0Xuw3BkDPk9I
|
||||
qkQKx3fqv97LPEzhyZYjDT5WvGrgZ1WDAN3booxXF3oA1H3GHQc4m/vcLatOtb8e
|
||||
nI59gMQLEbnp08cl873bAuNuM95EZieXTHNbwUnq5iybAgMBAAGjUzBRMB0GA1Ud
|
||||
DgQWBBQBKhJh8eWu0a4au9X/2fKhkFX2vjAfBgNVHSMEGDAWgBQBKhJh8eWu0a4a
|
||||
u9X/2fKhkFX2vjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBj
|
||||
3aCW0YPKukYgVK9cwN0IbVy/D0C1UPT4nupJcy/E0iC7MXPZ9D/SZxYQoAkdptdO
|
||||
xfI+RXkpQZLdODNx9uvV+cHyZHZyjtE5ENu/i5Rer2cWI/mSLZm5lUQyx+0KZ2Yu
|
||||
tEI1bsebDK30msa8QSTn0WidW9XhFnl3gRi4wRdimcQapOWYVs7ih+nAlSvng7NI
|
||||
XpAyRs8PIEbpDDBMWnldrX4TP6EWYUi49gCp8OUDRREKX3l6Ls1vZ02F34yHIt/7
|
||||
7IV/XSKG096bhW+icKBWV0IpcEsgTzPK1J1hMxgjhzIMxGboAeUU+kidthOob6Sd
|
||||
XQxaORfgM//NzX9LhUPk
|
||||
-----END CERTIFICATE-----
|
||||
`)
|
||||
|
||||
var serverKey = []byte(`-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEogIBAAKCAQEAxvA8skudfNdBrBsIFq+a4ySuzhNZE0y0jRBCmsfAY8zsoms/
|
||||
KwNiRpdlVBKYtlIw6/Qpu53fmCBFbPdSCATm+yxqjmwYdZBhd7uWmcS5LzSRPh6y
|
||||
1b1IWg6GytjVPlom6nPxCNw31JLda0iDb7/X5cExbtah3ri1oaMkswyhKTs2MaRY
|
||||
cI1UqJGSI0+EXndzrRc+4JdhOjgFntqqIeQsC2FXTFrSkdF7sNwZAz5PSKpECsd3
|
||||
6r/eyzxM4cmWIw0+Vrxq4GdVgwDd26KMVxd6ANR9xh0HOJv73C2rTrW/HpyOfYDE
|
||||
CxG56dPHJfO92wLjbjPeRGYnl0xzW8FJ6uYsmwIDAQABAoIBACi0BKcyQ3HElSJC
|
||||
kaAao+Uvnzh4yvPg8Nwf5JDIp/uDdTMyIEWLtrLczRWrjGVZYbsVROinP5VfnPTT
|
||||
kYwkfKINj2u+gC6lsNuPnRuvHXikF8eO/mYvCTur1zZvsQnF5kp4GGwIqr+qoPUP
|
||||
bB0UMndG1PdpoMryHe+JcrvTrLHDmCeH10TqOwMsQMLHYLkowvxwJWsmTY7/Qr5S
|
||||
Wm3PPpOcW2i0uyPVuyuv4yD1368fqnqJ8QFsQp1K6QtYsNnJ71Hut1/IoxK/e6hj
|
||||
5Z+byKtHVtmcLnABuoOT7BhleJNFBksX9sh83jid4tMBgci+zXNeGmgqo2EmaWAb
|
||||
agQslkECgYEA8B1rzjOHVQx/vwSzDa4XOrpoHQRfyElrGNz9JVBvnoC7AorezBXQ
|
||||
M9WTHQIFTGMjzD8pb+YJGi3gj93VN51r0SmJRxBaBRh1ZZI9kFiFzngYev8POgD3
|
||||
ygmlS3kTHCNxCK/CJkB+/jMBgtPj5ygDpCWVcTSuWlQFphePkW7jaaECgYEA1Blz
|
||||
ulqgAyJHZaqgcbcCsI2q6m527hVr9pjzNjIVmkwu38yS9RTCgdlbEVVDnS0hoifl
|
||||
+jVMEGXjF3xjyMvL50BKbQUH+KAa+V4n1WGlnZOxX9TMny8MBjEuSX2+362vQ3BX
|
||||
4vOlX00gvoc+sY+lrzvfx/OdPCHQGVYzoKCxhLsCgYA07HcviuIAV/HsO2/vyvhp
|
||||
xF5gTu+BqNUHNOZDDDid+ge+Jre2yfQLCL8VPLXIQW3Jff53IH/PGl+NtjphuLvj
|
||||
7UDJvgvpZZuymIojP6+2c3gJ3CASC9aR3JBnUzdoE1O9s2eaoMqc4scpe+SWtZYf
|
||||
3vzSZ+cqF6zrD/Rf/M35IQKBgHTU4E6ShPm09CcoaeC5sp2WK8OevZw/6IyZi78a
|
||||
r5Oiy18zzO97U/k6xVMy6F+38ILl/2Rn31JZDVJujniY6eSkIVsUHmPxrWoXV1HO
|
||||
y++U32uuSFiXDcSLarfIsE992MEJLSAynbF1Rsgsr3gXbGiuToJRyxbIeVy7gwzD
|
||||
94TpAoGAY4/PejWQj9psZfAhyk5dRGra++gYRQ/gK1IIc1g+Dd2/BxbT/RHr05GK
|
||||
6vwrfjsoRyMWteC1SsNs/CurjfQ/jqCfHNP5XPvxgd5Ec8sRJIiV7V5RTuWJsPu1
|
||||
+3K6cnKEyg+0ekYmLertRFIY6SwWmY1fyKgTvxudMcsBY7dC4xs=
|
||||
-----END RSA PRIVATE KEY-----
|
||||
`)
|
||||
|
||||
func writeTempFile(byts []byte) (string, error) {
|
||||
tmpf, err := os.CreateTemp(os.TempDir(), "rtsp-")
|
||||
if err != nil {
|
||||
|
|
@ -176,11 +124,11 @@ func TestSource(t *testing.T) {
|
|||
s.UDPRTCPAddress = "127.0.0.1:8003"
|
||||
|
||||
case "tls":
|
||||
serverCertFpath, err := writeTempFile(serverCert)
|
||||
serverCertFpath, err := writeTempFile(test.TLSCertPub)
|
||||
require.NoError(t, err)
|
||||
defer os.Remove(serverCertFpath)
|
||||
|
||||
serverKeyFpath, err := writeTempFile(serverKey)
|
||||
serverKeyFpath, err := writeTempFile(test.TLSCertKey)
|
||||
require.NoError(t, err)
|
||||
defer os.Remove(serverKeyFpath)
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,8 @@ import (
|
|||
"github.com/bluenviron/mediamtx/internal/unit"
|
||||
)
|
||||
|
||||
type readerFunc func(unit.Unit) error
|
||||
// ReadFunc is the callback passed to AddReader().
|
||||
type ReadFunc func(unit.Unit) error
|
||||
|
||||
// Stream is a media stream.
|
||||
// It stores tracks, readers and allows to write data to readers.
|
||||
|
|
@ -115,7 +116,7 @@ func (s *Stream) RTSPSStream(server *gortsplib.Server) *gortsplib.ServerStream {
|
|||
}
|
||||
|
||||
// AddReader adds a reader.
|
||||
func (s *Stream) AddReader(r *asyncwriter.Writer, medi *description.Media, forma format.Format, cb readerFunc) {
|
||||
func (s *Stream) AddReader(r *asyncwriter.Writer, medi *description.Media, forma format.Format, cb ReadFunc) {
|
||||
s.mutex.Lock()
|
||||
defer s.mutex.Unlock()
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ func unitSize(u unit.Unit) uint64 {
|
|||
type streamFormat struct {
|
||||
decodeErrLogger logger.Writer
|
||||
proc formatprocessor.Processor
|
||||
readers map[*asyncwriter.Writer]readerFunc
|
||||
readers map[*asyncwriter.Writer]ReadFunc
|
||||
}
|
||||
|
||||
func newStreamFormat(
|
||||
|
|
@ -42,13 +42,13 @@ func newStreamFormat(
|
|||
sf := &streamFormat{
|
||||
decodeErrLogger: decodeErrLogger,
|
||||
proc: proc,
|
||||
readers: make(map[*asyncwriter.Writer]readerFunc),
|
||||
readers: make(map[*asyncwriter.Writer]ReadFunc),
|
||||
}
|
||||
|
||||
return sf, nil
|
||||
}
|
||||
|
||||
func (sf *streamFormat) addReader(r *asyncwriter.Writer, cb readerFunc) {
|
||||
func (sf *streamFormat) addReader(r *asyncwriter.Writer, cb ReadFunc) {
|
||||
sf.readers[r] = cb
|
||||
}
|
||||
|
||||
|
|
|
|||
55
internal/test/tls_cert.go
Normal file
55
internal/test/tls_cert.go
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
package test
|
||||
|
||||
// TLSCertPub is the public key of a test certificate.
|
||||
var TLSCertPub = []byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIDazCCAlOgAwIBAgIUXw1hEC3LFpTsllv7D3ARJyEq7sIwDQYJKoZIhvcNAQEL
|
||||
BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
|
||||
GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yMDEyMTMxNzQ0NThaFw0zMDEy
|
||||
MTExNzQ0NThaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw
|
||||
HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3DQEB
|
||||
AQUAA4IBDwAwggEKAoIBAQDG8DyyS51810GsGwgWr5rjJK7OE1kTTLSNEEKax8Bj
|
||||
zOyiaz8rA2JGl2VUEpi2UjDr9Cm7nd+YIEVs91IIBOb7LGqObBh1kGF3u5aZxLkv
|
||||
NJE+HrLVvUhaDobK2NU+Wibqc/EI3DfUkt1rSINvv9flwTFu1qHeuLWhoySzDKEp
|
||||
OzYxpFhwjVSokZIjT4Red3OtFz7gl2E6OAWe2qoh5CwLYVdMWtKR0Xuw3BkDPk9I
|
||||
qkQKx3fqv97LPEzhyZYjDT5WvGrgZ1WDAN3booxXF3oA1H3GHQc4m/vcLatOtb8e
|
||||
nI59gMQLEbnp08cl873bAuNuM95EZieXTHNbwUnq5iybAgMBAAGjUzBRMB0GA1Ud
|
||||
DgQWBBQBKhJh8eWu0a4au9X/2fKhkFX2vjAfBgNVHSMEGDAWgBQBKhJh8eWu0a4a
|
||||
u9X/2fKhkFX2vjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBj
|
||||
3aCW0YPKukYgVK9cwN0IbVy/D0C1UPT4nupJcy/E0iC7MXPZ9D/SZxYQoAkdptdO
|
||||
xfI+RXkpQZLdODNx9uvV+cHyZHZyjtE5ENu/i5Rer2cWI/mSLZm5lUQyx+0KZ2Yu
|
||||
tEI1bsebDK30msa8QSTn0WidW9XhFnl3gRi4wRdimcQapOWYVs7ih+nAlSvng7NI
|
||||
XpAyRs8PIEbpDDBMWnldrX4TP6EWYUi49gCp8OUDRREKX3l6Ls1vZ02F34yHIt/7
|
||||
7IV/XSKG096bhW+icKBWV0IpcEsgTzPK1J1hMxgjhzIMxGboAeUU+kidthOob6Sd
|
||||
XQxaORfgM//NzX9LhUPk
|
||||
-----END CERTIFICATE-----
|
||||
`)
|
||||
|
||||
// TLSCertKey is the private key of a test certificate.
|
||||
var TLSCertKey = []byte(`-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEogIBAAKCAQEAxvA8skudfNdBrBsIFq+a4ySuzhNZE0y0jRBCmsfAY8zsoms/
|
||||
KwNiRpdlVBKYtlIw6/Qpu53fmCBFbPdSCATm+yxqjmwYdZBhd7uWmcS5LzSRPh6y
|
||||
1b1IWg6GytjVPlom6nPxCNw31JLda0iDb7/X5cExbtah3ri1oaMkswyhKTs2MaRY
|
||||
cI1UqJGSI0+EXndzrRc+4JdhOjgFntqqIeQsC2FXTFrSkdF7sNwZAz5PSKpECsd3
|
||||
6r/eyzxM4cmWIw0+Vrxq4GdVgwDd26KMVxd6ANR9xh0HOJv73C2rTrW/HpyOfYDE
|
||||
CxG56dPHJfO92wLjbjPeRGYnl0xzW8FJ6uYsmwIDAQABAoIBACi0BKcyQ3HElSJC
|
||||
kaAao+Uvnzh4yvPg8Nwf5JDIp/uDdTMyIEWLtrLczRWrjGVZYbsVROinP5VfnPTT
|
||||
kYwkfKINj2u+gC6lsNuPnRuvHXikF8eO/mYvCTur1zZvsQnF5kp4GGwIqr+qoPUP
|
||||
bB0UMndG1PdpoMryHe+JcrvTrLHDmCeH10TqOwMsQMLHYLkowvxwJWsmTY7/Qr5S
|
||||
Wm3PPpOcW2i0uyPVuyuv4yD1368fqnqJ8QFsQp1K6QtYsNnJ71Hut1/IoxK/e6hj
|
||||
5Z+byKtHVtmcLnABuoOT7BhleJNFBksX9sh83jid4tMBgci+zXNeGmgqo2EmaWAb
|
||||
agQslkECgYEA8B1rzjOHVQx/vwSzDa4XOrpoHQRfyElrGNz9JVBvnoC7AorezBXQ
|
||||
M9WTHQIFTGMjzD8pb+YJGi3gj93VN51r0SmJRxBaBRh1ZZI9kFiFzngYev8POgD3
|
||||
ygmlS3kTHCNxCK/CJkB+/jMBgtPj5ygDpCWVcTSuWlQFphePkW7jaaECgYEA1Blz
|
||||
ulqgAyJHZaqgcbcCsI2q6m527hVr9pjzNjIVmkwu38yS9RTCgdlbEVVDnS0hoifl
|
||||
+jVMEGXjF3xjyMvL50BKbQUH+KAa+V4n1WGlnZOxX9TMny8MBjEuSX2+362vQ3BX
|
||||
4vOlX00gvoc+sY+lrzvfx/OdPCHQGVYzoKCxhLsCgYA07HcviuIAV/HsO2/vyvhp
|
||||
xF5gTu+BqNUHNOZDDDid+ge+Jre2yfQLCL8VPLXIQW3Jff53IH/PGl+NtjphuLvj
|
||||
7UDJvgvpZZuymIojP6+2c3gJ3CASC9aR3JBnUzdoE1O9s2eaoMqc4scpe+SWtZYf
|
||||
3vzSZ+cqF6zrD/Rf/M35IQKBgHTU4E6ShPm09CcoaeC5sp2WK8OevZw/6IyZi78a
|
||||
r5Oiy18zzO97U/k6xVMy6F+38ILl/2Rn31JZDVJujniY6eSkIVsUHmPxrWoXV1HO
|
||||
y++U32uuSFiXDcSLarfIsE992MEJLSAynbF1Rsgsr3gXbGiuToJRyxbIeVy7gwzD
|
||||
94TpAoGAY4/PejWQj9psZfAhyk5dRGra++gYRQ/gK1IIc1g+Dd2/BxbT/RHr05GK
|
||||
6vwrfjsoRyMWteC1SsNs/CurjfQ/jqCfHNP5XPvxgd5Ec8sRJIiV7V5RTuWJsPu1
|
||||
+3K6cnKEyg+0ekYmLertRFIY6SwWmY1fyKgTvxudMcsBY7dC4xs=
|
||||
-----END RSA PRIVATE KEY-----
|
||||
`)
|
||||
Loading…
Add table
Add a link
Reference in a new issue