mirror of
https://github.com/rclone/rclone.git
synced 2024-11-22 16:34:30 +01:00
dlna: fake out implementation of X_MS_MediaReceiverRegistrar
Using the same responses as minidlna. Fixes #3502.
This commit is contained in:
parent
2f10472df3
commit
5f07bbf8ce
@ -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
|
||||||
|
@ -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>")
|
||||||
|
}
|
||||||
|
@ -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
27
cmd/serve/dlna/mrrs.go
Normal 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
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user