decode urls in requests

This commit is contained in:
aler9
2020-05-03 19:30:01 +02:00
parent 28603af339
commit aedfa068de
5 changed files with 35 additions and 18 deletions

View File

@@ -4,6 +4,7 @@ import (
"crypto/md5" "crypto/md5"
"encoding/hex" "encoding/hex"
"fmt" "fmt"
"net/url"
"strings" "strings"
) )
@@ -61,11 +62,11 @@ func NewAuthClient(header []string, user string, pass string) (*AuthClient, erro
// GenerateHeader generates an Authorization Header that allows to authenticate a request with // GenerateHeader generates an Authorization Header that allows to authenticate a request with
// the given method and path. // the given method and path.
func (ac *AuthClient) GenerateHeader(method Method, path string) []string { func (ac *AuthClient) GenerateHeader(method Method, ur *url.URL) []string {
ha1 := md5Hex(ac.user + ":" + ac.realm + ":" + ac.pass) ha1 := md5Hex(ac.user + ":" + ac.realm + ":" + ac.pass)
ha2 := md5Hex(string(method) + ":" + path) ha2 := md5Hex(string(method) + ":" + ur.String())
response := md5Hex(ha1 + ":" + ac.nonce + ":" + ha2) response := md5Hex(ha1 + ":" + ac.nonce + ":" + ha2)
return []string{fmt.Sprintf("Digest username=\"%s\", realm=\"%s\", nonce=\"%s\", uri=\"%s\", response=\"%s\"", return []string{fmt.Sprintf("Digest username=\"%s\", realm=\"%s\", nonce=\"%s\", uri=\"%s\", response=\"%s\"",
ac.user, ac.realm, ac.nonce, path, response)} ac.user, ac.realm, ac.nonce, ur.String(), response)}
} }

View File

@@ -4,6 +4,7 @@ import (
"crypto/rand" "crypto/rand"
"encoding/hex" "encoding/hex"
"fmt" "fmt"
"net/url"
) )
// AuthServer is an object that helps a server validating the credentials of a client. // AuthServer is an object that helps a server validating the credentials of a client.
@@ -35,7 +36,7 @@ func (as *AuthServer) GenerateHeader() []string {
// ValidateHeader validates the Authorization header sent by a client after receiving the // ValidateHeader validates the Authorization header sent by a client after receiving the
// WWW-Authenticate header provided by GenerateHeader(). // WWW-Authenticate header provided by GenerateHeader().
func (as *AuthServer) ValidateHeader(header []string, method Method, path string) error { func (as *AuthServer) ValidateHeader(header []string, method Method, ur *url.URL) error {
if len(header) != 1 { if len(header) != 1 {
return fmt.Errorf("Authorization header not provided") return fmt.Errorf("Authorization header not provided")
} }
@@ -82,12 +83,12 @@ func (as *AuthServer) ValidateHeader(header []string, method Method, path string
return fmt.Errorf("wrong username") return fmt.Errorf("wrong username")
} }
if inUri != path { if inUri != ur.String() {
return fmt.Errorf("wrong uri") return fmt.Errorf("wrong url")
} }
ha1 := md5Hex(as.user + ":" + as.realm + ":" + as.pass) ha1 := md5Hex(as.user + ":" + as.realm + ":" + as.pass)
ha2 := md5Hex(string(method) + ":" + path) ha2 := md5Hex(string(method) + ":" + ur.String())
response := md5Hex(ha1 + ":" + as.nonce + ":" + ha2) response := md5Hex(ha1 + ":" + as.nonce + ":" + ha2)
if inResponse != response { if inResponse != response {

View File

@@ -1,6 +1,7 @@
package gortsplib package gortsplib
import ( import (
"net/url"
"testing" "testing"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
@@ -12,8 +13,10 @@ func TestAuthClientServer(t *testing.T) {
ac, err := NewAuthClient(wwwAuthenticate, "testuser", "testpass") ac, err := NewAuthClient(wwwAuthenticate, "testuser", "testpass")
require.NoError(t, err) require.NoError(t, err)
authorization := ac.GenerateHeader(ANNOUNCE, "rtsp://myhost/mypath") authorization := ac.GenerateHeader(ANNOUNCE,
&url.URL{Scheme: "rtsp", Host: "myhost", Path: "mypath"})
err = as.ValidateHeader(authorization, ANNOUNCE, "rtsp://myhost/mypath") err = as.ValidateHeader(authorization, ANNOUNCE,
&url.URL{Scheme: "rtsp", Host: "myhost", Path: "mypath"})
require.NoError(t, err) require.NoError(t, err)
} }

View File

@@ -3,6 +3,7 @@ package gortsplib
import ( import (
"bufio" "bufio"
"fmt" "fmt"
"net/url"
) )
const ( const (
@@ -32,7 +33,7 @@ const (
// Request is a RTSP request. // Request is a RTSP request.
type Request struct { type Request struct {
Method Method Method Method
Url string Url *url.URL
Header Header Header Header
Content []byte Content []byte
} }
@@ -46,7 +47,7 @@ func readRequest(br *bufio.Reader) (*Request, error) {
} }
req.Method = Method(byts[:len(byts)-1]) req.Method = Method(byts[:len(byts)-1])
if len(req.Method) == 0 { if req.Method == "" {
return nil, fmt.Errorf("empty method") return nil, fmt.Errorf("empty method")
} }
@@ -54,12 +55,22 @@ func readRequest(br *bufio.Reader) (*Request, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
req.Url = string(byts[:len(byts)-1]) rawUrl := string(byts[:len(byts)-1])
if len(req.Url) == 0 { if rawUrl == "" {
return nil, fmt.Errorf("empty url") return nil, fmt.Errorf("empty url")
} }
ur, err := url.Parse(rawUrl)
if err != nil {
return nil, fmt.Errorf("unable to parse url '%s'", rawUrl)
}
req.Url = ur
if req.Url.Scheme != "rtsp" {
return nil, fmt.Errorf("invalid url scheme '%s'", req.Url.Scheme)
}
byts, err = readBytesLimited(br, '\r', _MAX_PROTOCOL_LENGTH) byts, err = readBytesLimited(br, '\r', _MAX_PROTOCOL_LENGTH)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -89,7 +100,7 @@ func readRequest(br *bufio.Reader) (*Request, error) {
} }
func (req *Request) write(bw *bufio.Writer) error { func (req *Request) write(bw *bufio.Writer) error {
_, err := bw.Write([]byte(string(req.Method) + " " + req.Url + " " + _RTSP_PROTO + "\r\n")) _, err := bw.Write([]byte(string(req.Method) + " " + req.Url.String() + " " + _RTSP_PROTO + "\r\n"))
if err != nil { if err != nil {
return err return err
} }

View File

@@ -3,6 +3,7 @@ package gortsplib
import ( import (
"bufio" "bufio"
"bytes" "bytes"
"net/url"
"testing" "testing"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
@@ -22,7 +23,7 @@ var casesRequest = []struct {
"\r\n"), "\r\n"),
&Request{ &Request{
Method: "OPTIONS", Method: "OPTIONS",
Url: "rtsp://example.com/media.mp4", Url: &url.URL{Scheme: "rtsp", Host: "example.com", Path: "/media.mp4"},
Header: Header{ Header: Header{
"CSeq": []string{"1"}, "CSeq": []string{"1"},
"Require": []string{"implicit-play"}, "Require": []string{"implicit-play"},
@@ -37,7 +38,7 @@ var casesRequest = []struct {
"\r\n"), "\r\n"),
&Request{ &Request{
Method: "DESCRIBE", Method: "DESCRIBE",
Url: "rtsp://example.com/media.mp4", Url: &url.URL{Scheme: "rtsp", Host: "example.com", Path: "/media.mp4"},
Header: Header{ Header: Header{
"CSeq": []string{"2"}, "CSeq": []string{"2"},
}, },
@@ -65,7 +66,7 @@ var casesRequest = []struct {
"m=video 2232 RTP/AVP 31\n"), "m=video 2232 RTP/AVP 31\n"),
&Request{ &Request{
Method: "ANNOUNCE", Method: "ANNOUNCE",
Url: "rtsp://example.com/media.mp4", Url: &url.URL{Scheme: "rtsp", Host: "example.com", Path: "/media.mp4"},
Header: Header{ Header: Header{
"CSeq": []string{"7"}, "CSeq": []string{"7"},
"Date": []string{"23 Jan 1997 15:35:06 GMT"}, "Date": []string{"23 Jan 1997 15:35:06 GMT"},
@@ -99,7 +100,7 @@ var casesRequest = []struct {
"jitter\n"), "jitter\n"),
&Request{ &Request{
Method: "GET_PARAMETER", Method: "GET_PARAMETER",
Url: "rtsp://example.com/media.mp4", Url: &url.URL{Scheme: "rtsp", Host: "example.com", Path: "/media.mp4"},
Header: Header{ Header: Header{
"CSeq": []string{"9"}, "CSeq": []string{"9"},
"Content-Type": []string{"text/parameters"}, "Content-Type": []string{"text/parameters"},