mirror of
https://github.com/truewhile/MeBox.git
synced 2026-09-28 03:06:38 +08:00
152 lines
5.1 KiB
Go
152 lines
5.1 KiB
Go
package service
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"io"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"strconv"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestCloud115HLSProxyRewriteManifest(t *testing.T) {
|
|
proxy := &Cloud115HLSProxy{sessions: map[string]*cloud115HLSSession{}}
|
|
session := &cloud115HLSSession{
|
|
ID: "sess",
|
|
MediaID: "media-1",
|
|
entries: map[string]string{},
|
|
}
|
|
manifest := "#EXTM3U\n#EXT-X-STREAM-INF:BANDWIDTH=1800000,RESOLUTION=1280x720\nhttps://cpats01.115.com/a.m3u8?u=1&se=2\n"
|
|
rewritten := proxy.rewriteManifest(session, manifest, "http://videoplay.115.com/m3u8/pc", "token=t&media_id=media-1")
|
|
if strings.Contains(rewritten, "cpats01.115.com") {
|
|
t.Fatalf("upstream URL leaked into rewritten manifest: %s", rewritten)
|
|
}
|
|
if !strings.Contains(rewritten, "/api/cloud115/hls/sess/e1?") {
|
|
t.Fatalf("proxy URL missing: %s", rewritten)
|
|
}
|
|
if !strings.Contains(rewritten, "media_id=media-1") || !strings.Contains(rewritten, "token=t") {
|
|
t.Fatalf("auth/media query missing: %s", rewritten)
|
|
}
|
|
if len(session.entries) != 1 {
|
|
t.Fatalf("session entries = %d, want 1", len(session.entries))
|
|
}
|
|
}
|
|
|
|
func TestCloud115HLSProxyRewriteKeyURI(t *testing.T) {
|
|
proxy := &Cloud115HLSProxy{sessions: map[string]*cloud115HLSSession{}}
|
|
session := &cloud115HLSSession{
|
|
ID: "sess",
|
|
MediaID: "media-1",
|
|
entries: map[string]string{},
|
|
}
|
|
manifest := `#EXTM3U
|
|
#EXT-X-KEY:METHOD=AES-128,URI="https://cpats01.115.com/key?k=1"
|
|
#EXTINF:10.0,
|
|
https://cpats01.115.com/seg.ts?x=1
|
|
`
|
|
rewritten := proxy.rewriteManifest(session, manifest, "https://cpats01.115.com/v.m3u8", "token=t&media_id=media-1")
|
|
if strings.Contains(rewritten, "cpats01.115.com") {
|
|
t.Fatalf("upstream URL leaked into rewritten key manifest: %s", rewritten)
|
|
}
|
|
if len(session.entries) != 2 {
|
|
t.Fatalf("session entries = %d, want 2", len(session.entries))
|
|
}
|
|
}
|
|
|
|
func TestIsAllowed115UpstreamHost(t *testing.T) {
|
|
for _, host := range []string{"videoplay.115.com", "cpats01.115.com", "cdn.115cdn.net"} {
|
|
if !isAllowed115UpstreamHost(host) {
|
|
t.Fatalf("host %q should be allowed", host)
|
|
}
|
|
}
|
|
for _, host := range []string{"", "evil.example.com", "115.com.evil.example.com"} {
|
|
if isAllowed115UpstreamHost(host) {
|
|
t.Fatalf("host %q should be rejected", host)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestCloud115HLSProxyServeChildRewritesVariant(t *testing.T) {
|
|
proxy := &Cloud115HLSProxy{
|
|
sessions: map[string]*cloud115HLSSession{},
|
|
}
|
|
proxy.client = &http.Client{Transport: roundTripFunc(func(req *http.Request) (*http.Response, error) {
|
|
body := "#EXTM3U\n#EXT-X-TARGETDURATION:10\nhttps://cpats01.115.com/seg.ts?x=1\n"
|
|
return &http.Response{
|
|
StatusCode: http.StatusOK,
|
|
Header: http.Header{
|
|
"Content-Type": []string{"application/vnd.apple.mpegurl"},
|
|
},
|
|
Body: io.NopCloser(strings.NewReader(body)),
|
|
Request: req,
|
|
}, nil
|
|
})}
|
|
session := &cloud115HLSSession{
|
|
ID: "sess",
|
|
MediaID: "media-1",
|
|
ExpiresAt: time.Now().Add(time.Hour),
|
|
entries: map[string]string{"e1": "https://cpats01.115.com/v.m3u8"},
|
|
next: 1,
|
|
}
|
|
proxy.sessions[session.ID] = session
|
|
req := httptest.NewRequest(http.MethodGet, "/api/cloud115/hls/sess/e1?media_id=media-1&token=t", nil)
|
|
rec := httptest.NewRecorder()
|
|
if err := proxy.ServeChild(context.Background(), rec, req, session.ID, "e1"); err != nil {
|
|
t.Fatalf("ServeChild: %v", err)
|
|
}
|
|
if rec.Code != http.StatusOK {
|
|
t.Fatalf("status = %d, want 200", rec.Code)
|
|
}
|
|
if !strings.Contains(rec.Body.String(), "/api/cloud115/hls/sess/e2?") {
|
|
t.Fatalf("rewritten variant missing proxy segment: %s", rec.Body.String())
|
|
}
|
|
if strings.Contains(rec.Body.String(), "cpats01.115.com") {
|
|
t.Fatalf("upstream URL leaked in variant: %s", rec.Body.String())
|
|
}
|
|
}
|
|
|
|
func TestCloud115HLSProxyServeChildStreamsRange(t *testing.T) {
|
|
payload := []byte("segment-bytes")
|
|
proxy := &Cloud115HLSProxy{
|
|
sessions: map[string]*cloud115HLSSession{},
|
|
}
|
|
proxy.client = &http.Client{Transport: roundTripFunc(func(req *http.Request) (*http.Response, error) {
|
|
return &http.Response{
|
|
StatusCode: http.StatusPartialContent,
|
|
Header: http.Header{
|
|
"Content-Type": []string{"video/mp2t"},
|
|
"Content-Range": []string{"bytes 0-12/100"},
|
|
"Content-Length": []string{strconv.Itoa(len(payload))},
|
|
},
|
|
Body: io.NopCloser(bytes.NewReader(payload)),
|
|
Request: req,
|
|
}, nil
|
|
})}
|
|
session := &cloud115HLSSession{
|
|
ID: "sess",
|
|
MediaID: "media-1",
|
|
ExpiresAt: time.Now().Add(time.Hour),
|
|
entries: map[string]string{"e1": "https://cpats01.115.com/seg.ts?x=1"},
|
|
next: 1,
|
|
}
|
|
proxy.sessions[session.ID] = session
|
|
req := httptest.NewRequest(http.MethodGet, "/api/cloud115/hls/sess/e1?media_id=media-1&token=t", nil)
|
|
req.Header.Set("Range", "bytes=0-12")
|
|
rec := httptest.NewRecorder()
|
|
if err := proxy.ServeChild(context.Background(), rec, req, session.ID, "e1"); err != nil {
|
|
t.Fatalf("ServeChild: %v", err)
|
|
}
|
|
if rec.Code != http.StatusPartialContent {
|
|
t.Fatalf("status = %d, want 206", rec.Code)
|
|
}
|
|
if rec.Header().Get("Content-Range") != "bytes 0-12/100" {
|
|
t.Fatalf("content-range = %q", rec.Header().Get("Content-Range"))
|
|
}
|
|
if !bytes.Equal(rec.Body.Bytes(), payload) {
|
|
t.Fatalf("payload = %q, want %q", rec.Body.Bytes(), payload)
|
|
}
|
|
}
|