Repository: bluenviron/gortsplib (go)

Issue:
rtsp CSeq contains a space in front of line translation characters
My camera, at the DESCRIBE request, returns CSeq, which contains a space mark, because of this, the condition in the waitResponse function of the client.go file does not work.
```go
                      if cseq, ok := res.Header["CSeq"]; !ok || len(cseq) != 1 || cseq[0] == requestCseqStr {
                               return res, nil
                      }
```
I used the patch:
[mypatch.patch](https://github.com/bluenviron/gortsplib/files/12817392/mypatch.patch)

Pull request:
client: support receiving responses with spaces in CSeq (#437)
Fixes #437

Patch:
diff --git a/client.go b/client.go
index 89ffeeb4..41dbdc7a 100644
--- a/client.go
+++ b/client.go
@@ -614,7 +614,7 @@ func (c *Client) waitResponse(requestCseqStr string) (*base.Response, error) {
 			c.OnResponse(res)
 
 			// accept response if CSeq equals request CSeq, or if CSeq is not present
-			if cseq, ok := res.Header["CSeq"]; !ok || len(cseq) != 1 || cseq[0] == requestCseqStr {
+			if cseq, ok := res.Header["CSeq"]; !ok || len(cseq) != 1 || strings.TrimSpace(cseq[0]) == requestCseqStr {
 				return res, nil
 			}
 


Test patch:
diff --git a/client_test.go b/client_test.go
index e1733d71..e9469170 100644
--- a/client_test.go
+++ b/client_test.go
@@ -99,6 +99,86 @@ func TestClientTLSSetServerName(t *testing.T) {
 	<-serverDone
 }
 
+func TestClientClose(t *testing.T) {
+	u, err := url.Parse("rtsp://localhost:8554/teststream")
+	require.NoError(t, err)
+
+	c := Client{}
+
+	err = c.Start(u.Scheme, u.Host)
+	require.NoError(t, err)
+
+	c.Close()
+
+	_, err = c.Options(u)
+	require.EqualError(t, err, "terminated")
+
+	_, _, err = c.Describe(u)
+	require.EqualError(t, err, "terminated")
+
+	_, err = c.Announce(u, nil)
+	require.EqualError(t, err, "terminated")
+
+	_, err = c.Setup(nil, nil, 0, 0)
+	require.EqualError(t, err, "terminated")
+
+	_, err = c.Play(nil)
+	require.EqualError(t, err, "terminated")
+
+	_, err = c.Record()
+	require.EqualError(t, err, "terminated")
+
+	_, err = c.Pause()
+	require.EqualError(t, err, "terminated")
+}
+
+func TestClientCloseDuringRequest(t *testing.T) {
+	l, err := net.Listen("tcp", "localhost:8554")
+	require.NoError(t, err)
+	defer l.Close()
+
+	requestReceived := make(chan struct{})
+	releaseConn := make(chan struct{})
+
+	serverDone := make(chan struct{})
+	defer func() { <-serverDone }()
+	go func() {
+		defer close(serverDone)
+
+		nconn, err := l.Accept()
+		require.NoError(t, err)
+		defer nconn.Close()
+		conn := conn.NewConn(nconn)
+
+		req, err := conn.ReadRequest()
+		require.NoError(t, err)
+		require.Equal(t, base.Options, req.Method)
+
+		close(requestReceived)
+		<-releaseConn
+	}()
+
+	u, err := url.Parse("rtsp://localhost:8554/teststream")
+	require.NoError(t, err)
+
+	c := Client{}
+
+	err = c.Start(u.Scheme, u.Host)
+	require.NoError(t, err)
+
+	optionsDone := make(chan struct{})
+	go func() {
+		defer close(optionsDone)
+		_, err := c.Options(u)
+		require.Error(t, err)
+	}()
+
+	<-requestReceived
+	c.Close()
+	<-optionsDone
+	close(releaseConn)
+}
+
 func TestClientSession(t *testing.T) {
 	l, err := net.Listen("tcp", "localhost:8554")
 	require.NoError(t, err)
@@ -236,6 +316,83 @@ func TestClientAuth(t *testing.T) {
 	require.NoError(t, err)
 }
 
+func TestClientCSeq(t *testing.T) {
+	for _, ca := range []string{
+		"different cseq",
+		"space at the end",
+	} {
+		t.Run(ca, func(t *testing.T) {
+			l, err := net.Listen("tcp", "localhost:8554")
+			require.NoError(t, err)
+			defer l.Close()
+
+			serverDone := make(chan struct{})
+			defer func() { <-serverDone }()
+			go func() {
+				defer close(serverDone)
+
+				nconn, err := l.Accept()
+				require.NoError(t, err)
+				defer nconn.Close()
+				conn := conn.NewConn(nconn)
+
+				req, err := conn.ReadRequest()
+				require.NoError(t, err)
+				require.Equal(t, base.Options, req.Method)
+
+				switch ca {
+				case "different cseq":
+					err = conn.WriteResponse(&base.Response{
+						StatusCode: base.StatusOK,
+						Header: base.Header{
+							"Public": base.HeaderValue{strings.Join([]string{
+								string(base.Describe),
+							}, ", ")},
+							"CSeq": base.HeaderValue{"150"},
+						},
+					})
+					require.NoError(t, err)
+
+					err = conn.WriteResponse(&base.Response{
+						StatusCode: base.StatusOK,
+						Header: base.Header{
+							"Public": base.HeaderValue{strings.Join([]string{
+								string(base.Describe),
+							}, ", ")},
+							"CSeq": req.Header["CSeq"],
+						},
+					})
+					require.NoError(t, err)
+
+				case "space at the end":
+					err = conn.WriteResponse(&base.Response{
+						StatusCode: base.StatusOK,
+						Header: base.Header{
+							"Public": base.HeaderValue{strings.Join([]string{
+								string(base.Describe),
+							}, ", ")},
+							"CSeq": base.HeaderValue{req.Header["CSeq"][0] + " "},
+						},
+					})
+					require.NoError(t, err)
+				}
+			}()
+
+			u, err := url.Parse("rtsp://localhost:8554/teststream")
+			require.NoError(t, err)
+
+			c := Client{}
+
+			err = c.Start(u.Scheme, u.Host)
+			require.NoError(t, err)
+			defer c.Close()
+
+			_, err = c.Options(u)
+			require.NoError(t, err)
+		})
+	}
+}
+
 func TestClientDescribeCharset(t *testing.T) {
 	l, err := net.Listen("tcp", "localhost:8554")
 	require.NoError(t, err)
@@ -296,86 +453,6 @@ func TestClientDescribeCharset(t *testing.T) {
 	require.NoError(t, err)
 }
 
-func TestClientClose(t *testing.T) {
-	u, err := url.Parse("rtsp://localhost:8554/teststream")
-	require.NoError(t, err)
-
-	c := Client{}
-
-	err = c.Start(u.Scheme, u.Host)
-	require.NoError(t, err)
-
-	c.Close()
-
-	_, err = c.Options(u)
-	require.EqualError(t, err, "terminated")
-
-	_, _, err = c.Describe(u)
-	require.EqualError(t, err, "terminated")
-
-	_, err = c.Announce(u, nil)
-	require.EqualError(t, err, "terminated")
-
-	_, err = c.Setup(nil, nil, 0, 0)
-	require.EqualError(t, err, "terminated")
-
-	_, err = c.Play(nil)
-	require.EqualError(t, err, "terminated")
-
-	_, err = c.Record()
-	require.EqualError(t, err, "terminated")
-
-	_, err = c.Pause()
-	require.EqualError(t, err, "terminated")
-}
-
-func TestClientCloseDuringRequest(t *testing.T) {
-	l, err := net.Listen("tcp", "localhost:8554")
-	require.NoError(t, err)
-	defer l.Close()
-
-	requestReceived := make(chan struct{})
-	releaseConn := make(chan struct{})
-
-	serverDone := make(chan struct{})
-	defer func() { <-serverDone }()
-	go func() {
-		defer close(serverDone)
-
-		nconn, err := l.Accept()
-		require.NoError(t, err)
-		defer nconn.Close()
-		conn := conn.NewConn(nconn)
-
-		req, err := conn.ReadRequest()
-		require.NoError(t, err)
-		require.Equal(t, base.Options, req.Method)
-
-		close(requestReceived)
-		<-releaseConn
-	}()
-
-	u, err := url.Parse("rtsp://localhost:8554/teststream")
-	require.NoError(t, err)
-
-	c := Client{}
-
-	err = c.Start(u.Scheme, u.Host)
-	require.NoError(t, err)
-
-	optionsDone := make(chan struct{})
-	go func() {
-		defer close(optionsDone)
-		_, err := c.Options(u)
-		require.Error(t, err)
-	}()
-
-	<-requestReceived
-	c.Close()
-	<-optionsDone
-	close(releaseConn)
-}
-
 func TestClientReplyToServerRequest(t *testing.T) {
 	for _, ca := range []string{"after response", "before response"} {
 		t.Run(ca, func(t *testing.T) {