github.com/cnotch/ipchub@v1.1.0/av/format/rtsp/response_test.go (about) 1 // Copyright (c) 2019,CAOHONGJU All rights reserved. 2 // Use of this source code is governed by a MIT-style 3 // license that can be found in the LICENSE file. 4 5 package rtsp 6 7 import ( 8 "bufio" 9 "bytes" 10 "reflect" 11 "regexp" 12 "strings" 13 "testing" 14 ) 15 16 func TestReadResponse(t *testing.T) { 17 tests := responseTestCases() 18 for _, tt := range tests { 19 t.Run(tt.name, func(t *testing.T) { 20 got, err := ReadResponse(bufio.NewReader(bytes.NewBufferString(tt.str))) 21 if err != nil { 22 t.Errorf("ReadResponse() error = %v", err) 23 return 24 } 25 if !reflect.DeepEqual(got, tt.resp) { 26 t.Errorf("ReadResponse() = %v, want %v", got, tt.resp) 27 } 28 }) 29 } 30 } 31 32 func TestResponse_Write(t *testing.T) { 33 tests := responseTestCases() 34 for _, tt := range tests { 35 t.Run(tt.name, func(t *testing.T) { 36 buf := bytes.NewBuffer(make([]byte, 0, 1024)) 37 err := tt.resp.Write(buf) 38 if err != nil { 39 t.Errorf("Response.Write() error = %v", err) 40 return 41 } 42 got := string(buf.Bytes()) 43 44 if got != tt.str { 45 t.Errorf("Response.Write() = %v, want %v", got, tt.str) 46 } 47 }) 48 } 49 } 50 51 type responseTestCase struct { 52 name string 53 str string 54 resp *Response 55 } 56 57 func responseTestCases() []responseTestCase { 58 var testCases []responseTestCase 59 60 var str = `RTSP/1.0 200 OK 61 CSeq: 1 62 Proxy-Require: gzipped-messages 63 Require: implicit-play 64 65 ` 66 str = strings.Replace(str, "\n", "\r\n", -1) 67 var header = make(Header) 68 header.Set("CSeq", "1") 69 header.Set("Require", "implicit-play") 70 header.Set("Proxy-Require", "gzipped-messages") 71 resp := new(Response) 72 resp.StatusCode = 200 73 resp.Status = "200 OK" 74 resp.Proto = "RTSP/1.0" 75 resp.Header = header 76 77 testCases = append(testCases, responseTestCase{"Single Value", str, resp}) 78 79 str = `RTSP/1.0 451 Invalid Parameter 80 CSeq: 1 81 Public: DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE 82 83 ` 84 str = strings.Replace(str, "\n", "\r\n", -1) 85 header = make(Header) 86 header.Set("CSeq", "1") 87 header.Set("Public", "DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE") 88 // header.Add("Public", "DESCRIBE") 89 // header.Add("Public", "SETUP") 90 // header.Add("Public", "TEARDOWN") 91 // header.Add("Public", "PLAY") 92 // header.Add("Public", "PAUSE") 93 94 resp = new(Response) 95 resp.StatusCode = 451 96 resp.Status = "451 Invalid Parameter" 97 resp.Proto = "RTSP/1.0" 98 resp.Header = header 99 100 testCases = append(testCases, responseTestCase{"Multi Value", str, resp}) 101 102 str = `RTSP/1.0 200 OK 103 CSeq: 431 104 Content-Length: 15 105 Content-Type: text/parameters 106 Session: 12345678 107 108 123456789012345` 109 str = strings.Replace(str, "\n", "\r\n", -1) 110 header = make(Header) 111 header.Set("CSeq", "431") 112 header.Set("Content-Type", "text/parameters") 113 header.Set("Session", "12345678") 114 header.Set("Content-Length", "15") 115 116 resp = new(Response) 117 resp.StatusCode = 200 118 resp.Status = "200 OK" 119 resp.Proto = "RTSP/1.0" 120 resp.Header = header 121 resp.Body = "123456789012345" 122 123 testCases = append(testCases, responseTestCase{"With Body", str, resp}) 124 125 return testCases 126 } 127 128 func Test_parseServerDigestAuthLine(t *testing.T) { 129 130 tests := []struct { 131 name string 132 auth string 133 wantRealm string 134 wantNonce string 135 wantOk bool 136 }{ 137 { 138 name: "digestparse", 139 auth: `Digest realm="Another Streaming Media", nonce="60a76a995a0cb012f1707abc188f60cb"`, 140 wantRealm: "Another Streaming Media", 141 wantNonce: "60a76a995a0cb012f1707abc188f60cb", 142 wantOk: true, 143 }, 144 } 145 for _, tt := range tests { 146 t.Run(tt.name, func(t *testing.T) { 147 resp := &Response{Header: make(Header)} 148 resp.Header.set(FieldWWWAuthenticate, tt.auth) 149 gotRealm, gotNonce, gotOk := resp.DigestAuth() 150 if gotRealm != tt.wantRealm { 151 t.Errorf("parseDigestAuthResp() gotRealm = %v, want %v", gotRealm, tt.wantRealm) 152 } 153 if gotNonce != tt.wantNonce { 154 t.Errorf("parseDigestAuthResp() gotNonce = %v, want %v", gotNonce, tt.wantNonce) 155 } 156 if gotOk != tt.wantOk { 157 t.Errorf("parseDigestAuthResp() gotOk = %v, want %v", gotOk, tt.wantOk) 158 } 159 }) 160 } 161 } 162 163 func Benchmark_Response_DigestAuth(b *testing.B) { 164 auth := `Digest realm="Another Streaming Media", nonce="60a76a995a0cb012f1707abc188f60cb"` 165 resp := &Response{Header: make(Header)} 166 resp.Header.set(FieldWWWAuthenticate, auth) 167 b.ResetTimer() 168 b.RunParallel(func(pb *testing.PB) { 169 for pb.Next() { 170 _, _, ok := resp.DigestAuth() 171 _ = ok 172 } 173 }) 174 } 175 176 func Benchmark_Regexp_DigestAuth(b *testing.B) { 177 auth := `Digest realm="Another Streaming Media", nonce="60a76a995a0cb012f1707abc188f60cb"` 178 b.ResetTimer() 179 b.RunParallel(func(pb *testing.PB) { 180 for pb.Next() { 181 realmRex := regexp.MustCompile(`realm="(.*?)"`) 182 nonceRex := regexp.MustCompile(`nonce="(.*?)"`) 183 realm := "" 184 nonce := "" 185 result1 := realmRex.FindStringSubmatch(auth) 186 result2 := nonceRex.FindStringSubmatch(auth) 187 188 if len(result1) == 2 { 189 realm = result1[1] 190 } 191 if len(result2) == 2 { 192 nonce = result2[1] 193 } 194 _ = realm 195 _ = nonce 196 } 197 }) 198 }