From 3ca94f9f9d76f2e7de5204300e8c12d33edaa1b9 Mon Sep 17 00:00:00 2001 From: aler9 <46489434+aler9@users.noreply.github.com> Date: Sun, 3 May 2020 14:40:06 +0200 Subject: [PATCH] simplify response handling --- go.mod | 2 +- go.sum | 4 +- server-client.go | 156 +++++++++++++++++------------------------------ 3 files changed, 59 insertions(+), 103 deletions(-) diff --git a/go.mod b/go.mod index fdaf61c0..fb098c3d 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.13 require ( github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 // indirect github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d // indirect - github.com/aler9/gortsplib v0.0.0-20200313131835-13b7bffbba39 + github.com/aler9/gortsplib v0.0.0-20200503123511-fc0216b54c90 gopkg.in/alecthomas/kingpin.v2 v2.2.6 gortc.io/sdp v0.17.0 ) diff --git a/go.sum b/go.sum index d6ed1493..b5e21b97 100644 --- a/go.sum +++ b/go.sum @@ -2,8 +2,8 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafo github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d h1:UQZhZ2O0vMHr2cI+DC1Mbh0TJxzA3RcLoMsFw+aXw7E= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= -github.com/aler9/gortsplib v0.0.0-20200313131835-13b7bffbba39 h1:9Vb9v7wBSp+mAtqb+5IJQRarQlycp2ksrv4wRrsMPZI= -github.com/aler9/gortsplib v0.0.0-20200313131835-13b7bffbba39/go.mod h1:YiIgmmv0ELkWUy11Jj2h5AgfqLCpy8sIX/l9MmS8+uw= +github.com/aler9/gortsplib v0.0.0-20200503123511-fc0216b54c90 h1:5aJvth91rfyL6okWPJKmnch6POwuNZKbgQZkt2cT7Gg= +github.com/aler9/gortsplib v0.0.0-20200503123511-fc0216b54c90/go.mod h1:YiIgmmv0ELkWUy11Jj2h5AgfqLCpy8sIX/l9MmS8+uw= github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw= diff --git a/server-client.go b/server-client.go index f5fae149..13032f71 100644 --- a/server-client.go +++ b/server-client.go @@ -218,23 +218,18 @@ func (c *serverClient) writeResDeadline(res *gortsplib.Response) { c.conn.WriteResponse(res) } -func (c *serverClient) writeResError(req *gortsplib.Request, err error) { +func (c *serverClient) writeResError(req *gortsplib.Request, code gortsplib.StatusCode, err error) { c.log("ERR: %s", err) + header := gortsplib.Header{} if cseq, ok := req.Header["CSeq"]; ok && len(cseq) == 1 { - c.writeResDeadline(&gortsplib.Response{ - StatusCode: 400, - Status: "Bad Request", - Header: gortsplib.Header{ - "CSeq": []string{cseq[0]}, - }, - }) - } else { - c.writeResDeadline(&gortsplib.Response{ - StatusCode: 400, - Status: "Bad Request", - }) + header["CSeq"] = []string{cseq[0]} } + + c.writeResDeadline(&gortsplib.Response{ + StatusCode: code, + Header: header, + }) } func (c *serverClient) handleRequest(req *gortsplib.Request) bool { @@ -242,13 +237,13 @@ func (c *serverClient) handleRequest(req *gortsplib.Request) bool { cseq, ok := req.Header["CSeq"] if !ok || len(cseq) != 1 { - c.writeResError(req, fmt.Errorf("cseq missing")) + c.writeResError(req, gortsplib.StatusBadRequest, fmt.Errorf("cseq missing")) return false } ur, err := url.Parse(req.Url) if err != nil { - c.writeResError(req, fmt.Errorf("unable to parse path '%s'", req.Url)) + c.writeResError(req, gortsplib.StatusBadRequest, fmt.Errorf("unable to parse path '%s'", req.Url)) return false } @@ -274,8 +269,7 @@ func (c *serverClient) handleRequest(req *gortsplib.Request) bool { // in any state c.writeResDeadline(&gortsplib.Response{ - StatusCode: 200, - Status: "OK", + StatusCode: gortsplib.StatusOK, Header: gortsplib.Header{ "CSeq": []string{cseq[0]}, "Public": []string{strings.Join([]string{ @@ -293,7 +287,7 @@ func (c *serverClient) handleRequest(req *gortsplib.Request) bool { case "DESCRIBE": if c.state != _CLIENT_STATE_STARTING { - c.writeResError(req, fmt.Errorf("client is in state '%d'", c.state)) + c.writeResError(req, gortsplib.StatusBadRequest, fmt.Errorf("client is in state '%d'", c.state)) return false } @@ -309,13 +303,12 @@ func (c *serverClient) handleRequest(req *gortsplib.Request) bool { return pub.streamSdpText, nil }() if err != nil { - c.writeResError(req, err) + c.writeResError(req, gortsplib.StatusBadRequest, err) return false } c.writeResDeadline(&gortsplib.Response{ - StatusCode: 200, - Status: "OK", + StatusCode: gortsplib.StatusOK, Header: gortsplib.Header{ "CSeq": []string{cseq[0]}, "Content-Base": []string{req.Url}, @@ -327,7 +320,7 @@ func (c *serverClient) handleRequest(req *gortsplib.Request) bool { case "ANNOUNCE": if c.state != _CLIENT_STATE_STARTING { - c.writeResError(req, fmt.Errorf("client is in state '%d'", c.state)) + c.writeResError(req, gortsplib.StatusBadRequest, fmt.Errorf("client is in state '%d'", c.state)) return false } @@ -345,8 +338,7 @@ func (c *serverClient) handleRequest(req *gortsplib.Request) bool { } c.writeResDeadline(&gortsplib.Response{ - StatusCode: 401, - Status: "Unauthorized", + StatusCode: gortsplib.StatusUnauthorized, Header: gortsplib.Header{ "CSeq": []string{cseq[0]}, "WWW-Authenticate": c.as.GenerateHeader(), @@ -363,18 +355,18 @@ func (c *serverClient) handleRequest(req *gortsplib.Request) bool { ct, ok := req.Header["Content-Type"] if !ok || len(ct) != 1 { - c.writeResError(req, fmt.Errorf("Content-Type header missing")) + c.writeResError(req, gortsplib.StatusBadRequest, fmt.Errorf("Content-Type header missing")) return false } if ct[0] != "application/sdp" { - c.writeResError(req, fmt.Errorf("unsupported Content-Type '%s'", ct)) + c.writeResError(req, gortsplib.StatusBadRequest, fmt.Errorf("unsupported Content-Type '%s'", ct)) return false } sdpParsed, err := sdpParse(req.Content) if err != nil { - c.writeResError(req, fmt.Errorf("invalid SDP: %s", err)) + c.writeResError(req, gortsplib.StatusBadRequest, fmt.Errorf("invalid SDP: %s", err)) return false } @@ -397,13 +389,12 @@ func (c *serverClient) handleRequest(req *gortsplib.Request) bool { return nil }() if err != nil { - c.writeResError(req, err) + c.writeResError(req, gortsplib.StatusBadRequest, err) return false } c.writeResDeadline(&gortsplib.Response{ - StatusCode: 200, - Status: "OK", + StatusCode: gortsplib.StatusOK, Header: gortsplib.Header{ "CSeq": []string{cseq[0]}, }, @@ -413,14 +404,14 @@ func (c *serverClient) handleRequest(req *gortsplib.Request) bool { case "SETUP": tsRaw, ok := req.Header["Transport"] if !ok || len(tsRaw) != 1 { - c.writeResError(req, fmt.Errorf("transport header missing")) + c.writeResError(req, gortsplib.StatusBadRequest, fmt.Errorf("transport header missing")) return false } th := gortsplib.ReadHeaderTransport(tsRaw[0]) if _, ok := th["unicast"]; !ok { - c.writeResError(req, fmt.Errorf("transport header does not contain unicast")) + c.writeResError(req, gortsplib.StatusBadRequest, fmt.Errorf("transport header does not contain unicast")) return false } @@ -440,25 +431,18 @@ func (c *serverClient) handleRequest(req *gortsplib.Request) bool { return false }() { if _, ok := c.p.protocols[_STREAM_PROTOCOL_UDP]; !ok { - c.log("ERR: udp streaming is disabled") - c.writeResDeadline(&gortsplib.Response{ - StatusCode: 461, - Status: "Unsupported Transport", - Header: gortsplib.Header{ - "CSeq": []string{cseq[0]}, - }, - }) + c.writeResError(req, gortsplib.StatusUnsupportedTransport, fmt.Errorf("UDP streaming is disabled")) return false } rtpPort, rtcpPort := th.GetPorts("client_port") if rtpPort == 0 || rtcpPort == 0 { - c.writeResError(req, fmt.Errorf("transport header does not have valid client ports (%s)", tsRaw[0])) + c.writeResError(req, gortsplib.StatusBadRequest, fmt.Errorf("transport header does not have valid client ports (%s)", tsRaw[0])) return false } if c.path != "" && path != c.path { - c.writeResError(req, fmt.Errorf("path has changed")) + c.writeResError(req, gortsplib.StatusBadRequest, fmt.Errorf("path has changed")) return false } @@ -490,13 +474,12 @@ func (c *serverClient) handleRequest(req *gortsplib.Request) bool { return nil }() if err != nil { - c.writeResError(req, err) + c.writeResError(req, gortsplib.StatusBadRequest, err) return false } c.writeResDeadline(&gortsplib.Response{ - StatusCode: 200, - Status: "OK", + StatusCode: gortsplib.StatusOK, Header: gortsplib.Header{ "CSeq": []string{cseq[0]}, "Transport": []string{strings.Join([]string{ @@ -513,19 +496,12 @@ func (c *serverClient) handleRequest(req *gortsplib.Request) bool { // play via TCP } else if _, ok := th["RTP/AVP/TCP"]; ok { if _, ok := c.p.protocols[_STREAM_PROTOCOL_TCP]; !ok { - c.log("ERR: tcp streaming is disabled") - c.writeResDeadline(&gortsplib.Response{ - StatusCode: 461, - Status: "Unsupported Transport", - Header: gortsplib.Header{ - "CSeq": []string{cseq[0]}, - }, - }) + c.writeResError(req, gortsplib.StatusUnsupportedTransport, fmt.Errorf("TCP streaming is disabled")) return false } if c.path != "" && path != c.path { - c.writeResError(req, fmt.Errorf("path has changed")) + c.writeResError(req, gortsplib.StatusBadRequest, fmt.Errorf("path has changed")) return false } @@ -557,15 +533,14 @@ func (c *serverClient) handleRequest(req *gortsplib.Request) bool { return nil }() if err != nil { - c.writeResError(req, err) + c.writeResError(req, gortsplib.StatusBadRequest, err) return false } interleaved := fmt.Sprintf("%d-%d", ((len(c.streamTracks) - 1) * 2), ((len(c.streamTracks)-1)*2)+1) c.writeResDeadline(&gortsplib.Response{ - StatusCode: 200, - Status: "OK", + StatusCode: gortsplib.StatusOK, Header: gortsplib.Header{ "CSeq": []string{cseq[0]}, "Transport": []string{strings.Join([]string{ @@ -579,19 +554,19 @@ func (c *serverClient) handleRequest(req *gortsplib.Request) bool { return true } else { - c.writeResError(req, fmt.Errorf("transport header does not contain a valid protocol (RTP/AVP, RTP/AVP/UDP or RTP/AVP/TCP) (%s)", tsRaw[0])) + c.writeResError(req, gortsplib.StatusBadRequest, fmt.Errorf("transport header does not contain a valid protocol (RTP/AVP, RTP/AVP/UDP or RTP/AVP/TCP) (%s)", tsRaw[0])) return false } // record case _CLIENT_STATE_ANNOUNCE, _CLIENT_STATE_PRE_RECORD: if _, ok := th["mode=record"]; !ok { - c.writeResError(req, fmt.Errorf("transport header does not contain mode=record")) + c.writeResError(req, gortsplib.StatusBadRequest, fmt.Errorf("transport header does not contain mode=record")) return false } if path != c.path { - c.writeResError(req, fmt.Errorf("path has changed")) + c.writeResError(req, gortsplib.StatusBadRequest, fmt.Errorf("path has changed")) return false } @@ -608,20 +583,13 @@ func (c *serverClient) handleRequest(req *gortsplib.Request) bool { return false }() { if _, ok := c.p.protocols[_STREAM_PROTOCOL_UDP]; !ok { - c.log("ERR: udp streaming is disabled") - c.writeResDeadline(&gortsplib.Response{ - StatusCode: 461, - Status: "Unsupported Transport", - Header: gortsplib.Header{ - "CSeq": []string{cseq[0]}, - }, - }) + c.writeResError(req, gortsplib.StatusUnsupportedTransport, fmt.Errorf("UDP streaming is disabled")) return false } rtpPort, rtcpPort := th.GetPorts("client_port") if rtpPort == 0 || rtcpPort == 0 { - c.writeResError(req, fmt.Errorf("transport header does not have valid client ports (%s)", tsRaw[0])) + c.writeResError(req, gortsplib.StatusBadRequest, fmt.Errorf("transport header does not have valid client ports (%s)", tsRaw[0])) return false } @@ -647,13 +615,12 @@ func (c *serverClient) handleRequest(req *gortsplib.Request) bool { return nil }() if err != nil { - c.writeResError(req, err) + c.writeResError(req, gortsplib.StatusBadRequest, err) return false } c.writeResDeadline(&gortsplib.Response{ - StatusCode: 200, - Status: "OK", + StatusCode: gortsplib.StatusOK, Header: gortsplib.Header{ "CSeq": []string{cseq[0]}, "Transport": []string{strings.Join([]string{ @@ -670,14 +637,7 @@ func (c *serverClient) handleRequest(req *gortsplib.Request) bool { // record via TCP } else if _, ok := th["RTP/AVP/TCP"]; ok { if _, ok := c.p.protocols[_STREAM_PROTOCOL_TCP]; !ok { - c.log("ERR: tcp streaming is disabled") - c.writeResDeadline(&gortsplib.Response{ - StatusCode: 461, - Status: "Unsupported Transport", - Header: gortsplib.Header{ - "CSeq": []string{cseq[0]}, - }, - }) + c.writeResError(req, gortsplib.StatusUnsupportedTransport, fmt.Errorf("TCP streaming is disabled")) return false } @@ -714,13 +674,12 @@ func (c *serverClient) handleRequest(req *gortsplib.Request) bool { return nil }() if err != nil { - c.writeResError(req, err) + c.writeResError(req, gortsplib.StatusBadRequest, err) return false } c.writeResDeadline(&gortsplib.Response{ - StatusCode: 200, - Status: "OK", + StatusCode: gortsplib.StatusOK, Header: gortsplib.Header{ "CSeq": []string{cseq[0]}, "Transport": []string{strings.Join([]string{ @@ -734,23 +693,23 @@ func (c *serverClient) handleRequest(req *gortsplib.Request) bool { return true } else { - c.writeResError(req, fmt.Errorf("transport header does not contain a valid protocol (RTP/AVP, RTP/AVP/UDP or RTP/AVP/TCP) (%s)", tsRaw[0])) + c.writeResError(req, gortsplib.StatusBadRequest, fmt.Errorf("transport header does not contain a valid protocol (RTP/AVP, RTP/AVP/UDP or RTP/AVP/TCP) (%s)", tsRaw[0])) return false } default: - c.writeResError(req, fmt.Errorf("client is in state '%d'", c.state)) + c.writeResError(req, gortsplib.StatusBadRequest, fmt.Errorf("client is in state '%d'", c.state)) return false } case "PLAY": if c.state != _CLIENT_STATE_PRE_PLAY { - c.writeResError(req, fmt.Errorf("client is in state '%d'", c.state)) + c.writeResError(req, gortsplib.StatusBadRequest, fmt.Errorf("client is in state '%d'", c.state)) return false } if path != c.path { - c.writeResError(req, fmt.Errorf("path has changed")) + c.writeResError(req, gortsplib.StatusBadRequest, fmt.Errorf("path has changed")) return false } @@ -770,7 +729,7 @@ func (c *serverClient) handleRequest(req *gortsplib.Request) bool { return nil }() if err != nil { - c.writeResError(req, err) + c.writeResError(req, gortsplib.StatusBadRequest, err) return false } @@ -778,8 +737,7 @@ func (c *serverClient) handleRequest(req *gortsplib.Request) bool { // otherwise, in case of TCP connections, RTP packets could be written // before the response c.writeResDeadline(&gortsplib.Response{ - StatusCode: 200, - Status: "OK", + StatusCode: gortsplib.StatusOK, Header: gortsplib.Header{ "CSeq": []string{cseq[0]}, "Session": []string{"12345678"}, @@ -826,12 +784,12 @@ func (c *serverClient) handleRequest(req *gortsplib.Request) bool { case "PAUSE": if c.state != _CLIENT_STATE_PLAY { - c.writeResError(req, fmt.Errorf("client is in state '%d'", c.state)) + c.writeResError(req, gortsplib.StatusBadRequest, fmt.Errorf("client is in state '%d'", c.state)) return false } if path != c.path { - c.writeResError(req, fmt.Errorf("path has changed")) + c.writeResError(req, gortsplib.StatusBadRequest, fmt.Errorf("path has changed")) return false } @@ -842,8 +800,7 @@ func (c *serverClient) handleRequest(req *gortsplib.Request) bool { c.p.mutex.Unlock() c.writeResDeadline(&gortsplib.Response{ - StatusCode: 200, - Status: "OK", + StatusCode: gortsplib.StatusOK, Header: gortsplib.Header{ "CSeq": []string{cseq[0]}, "Session": []string{"12345678"}, @@ -853,12 +810,12 @@ func (c *serverClient) handleRequest(req *gortsplib.Request) bool { case "RECORD": if c.state != _CLIENT_STATE_PRE_RECORD { - c.writeResError(req, fmt.Errorf("client is in state '%d'", c.state)) + c.writeResError(req, gortsplib.StatusBadRequest, fmt.Errorf("client is in state '%d'", c.state)) return false } if path != c.path { - c.writeResError(req, fmt.Errorf("path has changed")) + c.writeResError(req, gortsplib.StatusBadRequest, fmt.Errorf("path has changed")) return false } @@ -873,13 +830,12 @@ func (c *serverClient) handleRequest(req *gortsplib.Request) bool { return nil }() if err != nil { - c.writeResError(req, err) + c.writeResError(req, gortsplib.StatusBadRequest, err) return false } c.writeResDeadline(&gortsplib.Response{ - StatusCode: 200, - Status: "OK", + StatusCode: gortsplib.StatusOK, Header: gortsplib.Header{ "CSeq": []string{cseq[0]}, "Session": []string{"12345678"}, @@ -928,7 +884,7 @@ func (c *serverClient) handleRequest(req *gortsplib.Request) bool { return false default: - c.writeResError(req, fmt.Errorf("unhandled method '%s'", req.Method)) + c.writeResError(req, gortsplib.StatusBadRequest, fmt.Errorf("unhandled method '%s'", req.Method)) return false } }