mirror of
https://github.com/rclone/rclone.git
synced 2024-12-22 23:22:08 +01:00
dlna: fix SOAP action header parsing - fixes #6354
Changes in github.com/anacrolix/dms changed upnp.ServiceURN to include a namespace identifier. This identifier was previously hardcoded, but is now parsed out of the URN. The old SOAP action header parsing logic was duplicated in rclone and did not handle this field. Resulting responses included a URN with an empty namespace identifier, breaking clients.
This commit is contained in:
parent
5788d3fc29
commit
f675da9053
@ -186,7 +186,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 := parseActionHTTPHeader(soapActionString)
|
soapAction, err := upnp.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
|
||||||
|
@ -119,6 +119,8 @@ func TestContentDirectoryBrowseMetadata(t *testing.T) {
|
|||||||
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
||||||
body, err := ioutil.ReadAll(resp.Body)
|
body, err := ioutil.ReadAll(resp.Body)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
// should contain an appropriate URN
|
||||||
|
require.Contains(t, string(body), "urn:schemas-upnp-org:service:ContentDirectory:1")
|
||||||
// expect a <container> element
|
// expect a <container> element
|
||||||
require.Contains(t, string(body), html.EscapeString("<container "))
|
require.Contains(t, string(body), html.EscapeString("<container "))
|
||||||
require.NotContains(t, string(body), html.EscapeString("<item "))
|
require.NotContains(t, string(body), html.EscapeString("<item "))
|
||||||
|
@ -3,7 +3,6 @@ package dlna
|
|||||||
import (
|
import (
|
||||||
"crypto/md5"
|
"crypto/md5"
|
||||||
"encoding/xml"
|
"encoding/xml"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
@ -12,9 +11,6 @@ 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"
|
||||||
@ -89,36 +85,6 @@ 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
|
||||||
|
Loading…
Reference in New Issue
Block a user