dlna: fake out implementation of X_MS_MediaReceiverRegistrar

Using the same responses as minidlna.

Fixes #3502.
This commit is contained in:
Dan Walters 2019-09-14 14:03:48 -05:00 committed by Nick Craig-Wood
parent 2f10472df3
commit 5f07bbf8ce
4 changed files with 86 additions and 1 deletions

View File

@ -116,6 +116,9 @@ func newServer(f fs.Fs, opt *dlnaflags.Options) *server {
"ConnectionManager": &connectionManagerService{ "ConnectionManager": &connectionManagerService{
server: s, server: s,
}, },
"X_MS_MediaReceiverRegistrar": &mediaReceiverRegistrarService{
server: s,
},
} }
// Setup the various http routes. // Setup the various http routes.
@ -248,7 +251,7 @@ func (s *server) rootDescHandler(w http.ResponseWriter, r *http.Request) {
// Handle a service control HTTP request. // Handle a service control HTTP request.
func (s *server) serviceControlHandler(w http.ResponseWriter, r *http.Request) { func (s *server) serviceControlHandler(w http.ResponseWriter, r *http.Request) {
soapActionString := r.Header.Get("SOAPACTION") soapActionString := r.Header.Get("SOAPACTION")
soapAction, err := upnp.ParseActionHTTPHeader(soapActionString) soapAction, err := parseActionHTTPHeader(soapActionString)
if err != nil { if err != nil {
serveError(s, w, "Could not parse SOAPACTION header", err) serveError(s, w, "Could not parse SOAPACTION header", err)
return return

View File

@ -1,6 +1,7 @@
package dlna package dlna
import ( import (
"bytes"
"context" "context"
"fmt" "fmt"
"html" "html"
@ -11,6 +12,8 @@ import (
"strings" "strings"
"testing" "testing"
"github.com/anacrolix/dms/soap"
"github.com/rclone/rclone/vfs" "github.com/rclone/rclone/vfs"
_ "github.com/rclone/rclone/backend/local" _ "github.com/rclone/rclone/backend/local"
@ -125,3 +128,21 @@ func TestContentDirectoryBrowseMetadata(t *testing.T) {
// with a non-zero childCount // with a non-zero childCount
require.Contains(t, string(body), html.EscapeString(`childCount="1"`)) require.Contains(t, string(body), html.EscapeString(`childCount="1"`))
} }
// Check that the X_MS_MediaReceiverRegistrar is faked out properly.
func TestMediaReceiverRegistrarService(t *testing.T) {
env := soap.Envelope{
Body: soap.Body{
Action: []byte("RegisterDevice"),
},
}
req, err := http.NewRequest("POST", testURL+"ctl", bytes.NewReader(mustMarshalXML(env)))
require.NoError(t, err)
req.Header.Set("SOAPACTION", `"urn:microsoft.com:service:X_MS_MediaReceiverRegistrar:1#RegisterDevice"`)
resp, err := http.DefaultClient.Do(req)
require.NoError(t, err)
assert.Equal(t, http.StatusOK, resp.StatusCode)
body, err := ioutil.ReadAll(resp.Body)
require.NoError(t, err)
require.Contains(t, string(body), "<RegistrationRespMsg>")
}

View File

@ -3,6 +3,7 @@ package dlna
import ( import (
"crypto/md5" "crypto/md5"
"encoding/xml" "encoding/xml"
"errors"
"fmt" "fmt"
"io" "io"
"log" "log"
@ -11,6 +12,9 @@ import (
"net/http/httptest" "net/http/httptest"
"net/http/httputil" "net/http/httputil"
"os" "os"
"regexp"
"strconv"
"strings"
"github.com/anacrolix/dms/soap" "github.com/anacrolix/dms/soap"
"github.com/anacrolix/dms/upnp" "github.com/anacrolix/dms/upnp"
@ -85,6 +89,36 @@ func marshalSOAPResponse(sa upnp.SoapAction, args map[string]string) []byte {
sa.Action, sa.ServiceURN.String(), mustMarshalXML(soapArgs))) sa.Action, sa.ServiceURN.String(), mustMarshalXML(soapArgs)))
} }
var serviceURNRegexp = regexp.MustCompile(`:service:(\w+):(\d+)$`)
func parseServiceType(s string) (ret upnp.ServiceURN, err error) {
matches := serviceURNRegexp.FindStringSubmatch(s)
if matches == nil {
err = errors.New(s)
return
}
if len(matches) != 3 {
log.Panicf("Invalid serviceURNRegexp ?")
}
ret.Type = matches[1]
ret.Version, err = strconv.ParseUint(matches[2], 0, 0)
return
}
func parseActionHTTPHeader(s string) (ret upnp.SoapAction, err error) {
if s[0] != '"' || s[len(s)-1] != '"' {
return
}
s = s[1 : len(s)-1]
hashIndex := strings.LastIndex(s, "#")
if hashIndex == -1 {
return
}
ret.Action = s[hashIndex+1:]
ret.ServiceURN, err = parseServiceType(s[:hashIndex])
return
}
type loggingResponseWriter struct { type loggingResponseWriter struct {
http.ResponseWriter http.ResponseWriter
request *http.Request request *http.Request

27
cmd/serve/dlna/mrrs.go Normal file
View File

@ -0,0 +1,27 @@
package dlna
import (
"net/http"
"github.com/anacrolix/dms/upnp"
)
type mediaReceiverRegistrarService struct {
*server
upnp.Eventing
}
func (mrrs *mediaReceiverRegistrarService) Handle(action string, argsXML []byte, r *http.Request) (map[string]string, error) {
switch action {
case "IsAuthorized", "IsValidated":
return map[string]string{
"Result": "1",
}, nil
case "RegisterDevice":
return map[string]string{
"RegistrationRespMsg": mrrs.RootDeviceUUID,
}, nil
default:
return nil, upnp.InvalidActionError
}
}