forked from bluenviron/gortsplib
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathresponse.go
217 lines (187 loc) · 7.82 KB
/
response.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
package gortsplib
import (
"bufio"
"fmt"
"strconv"
)
// StatusCode is the status code of a RTSP response.
type StatusCode int
// standard status codes
const (
StatusContinue StatusCode = 100
StatusOK StatusCode = 200
StatusMovedPermanently StatusCode = 301
StatusFound StatusCode = 302
StatusSeeOther StatusCode = 303
StatusNotModified StatusCode = 304
StatusUseProxy StatusCode = 305
StatusBadRequest StatusCode = 400
StatusUnauthorized StatusCode = 401
StatusPaymentRequired StatusCode = 402
StatusForbidden StatusCode = 403
StatusNotFound StatusCode = 404
StatusMethodNotAllowed StatusCode = 405
StatusNotAcceptable StatusCode = 406
StatusProxyAuthRequired StatusCode = 407
StatusRequestTimeout StatusCode = 408
StatusGone StatusCode = 410
StatusPreconditionFailed StatusCode = 412
StatusRequestEntityTooLarge StatusCode = 413
StatusRequestURITooLong StatusCode = 414
StatusUnsupportedMediaType StatusCode = 415
StatusParameterNotUnderstood StatusCode = 451
StatusNotEnoughBandwidth StatusCode = 453
StatusSessionNotFound StatusCode = 454
StatusMethodNotValidInThisState StatusCode = 455
StatusHeaderFieldNotValidForResource StatusCode = 456
StatusInvalidRange StatusCode = 457
StatusParameterIsReadOnly StatusCode = 458
StatusAggregateOperationNotAllowed StatusCode = 459
StatusOnlyAggregateOperationAllowed StatusCode = 460
StatusUnsupportedTransport StatusCode = 461
StatusDestinationUnreachable StatusCode = 462
StatusDestinationProhibited StatusCode = 463
StatusDataTransportNotReadyYet StatusCode = 464
StatusNotificationReasonUnknown StatusCode = 465
StatusKeyManagementError StatusCode = 466
StatusConnectionAuthorizationRequired StatusCode = 470
StatusConnectionCredentialsNotAccepted StatusCode = 471
StatusFailureToEstablishSecureConnection StatusCode = 472
StatusInternalServerError StatusCode = 500
StatusNotImplemented StatusCode = 501
StatusBadGateway StatusCode = 502
StatusServiceUnavailable StatusCode = 503
StatusGatewayTimeout StatusCode = 504
StatusRTSPVersionNotSupported StatusCode = 505
StatusOptionNotSupported StatusCode = 551
StatusProxyUnavailable StatusCode = 553
)
// StatusMessages contains the status messages associated with each status code.
var StatusMessages = statusMessages
var statusMessages = map[StatusCode]string{
StatusContinue: "Continue",
StatusOK: "OK",
StatusMovedPermanently: "Moved Permanently",
StatusFound: "Found",
StatusSeeOther: "See Other",
StatusNotModified: "Not Modified",
StatusUseProxy: "Use Proxy",
StatusBadRequest: "Bad Request",
StatusUnauthorized: "Unauthorized",
StatusPaymentRequired: "Payment Required",
StatusForbidden: "Forbidden",
StatusNotFound: "Not Found",
StatusMethodNotAllowed: "Method Not Allowed",
StatusNotAcceptable: "Not Acceptable",
StatusProxyAuthRequired: "Proxy Auth Required",
StatusRequestTimeout: "Request Timeout",
StatusGone: "Gone",
StatusPreconditionFailed: "Precondition Failed",
StatusRequestEntityTooLarge: "Request Entity Too Large",
StatusRequestURITooLong: "Request URI Too Long",
StatusUnsupportedMediaType: "Unsupported Media Type",
StatusParameterNotUnderstood: "Parameter Not Understood",
StatusNotEnoughBandwidth: "Not Enough Bandwidth",
StatusSessionNotFound: "Session Not Found",
StatusMethodNotValidInThisState: "Method Not Valid In This State",
StatusHeaderFieldNotValidForResource: "Header Field Not Valid for Resource",
StatusInvalidRange: "Invalid Range",
StatusParameterIsReadOnly: "Parameter Is Read-Only",
StatusAggregateOperationNotAllowed: "Aggregate Operation Not Allowed",
StatusOnlyAggregateOperationAllowed: "Only Aggregate Operation Allowed",
StatusUnsupportedTransport: "Unsupported Transport",
StatusDestinationUnreachable: "Destination Unreachable",
StatusDestinationProhibited: "Destination Prohibited",
StatusDataTransportNotReadyYet: "Data Transport Not Ready Yet",
StatusNotificationReasonUnknown: "Notification Reason Unknown",
StatusKeyManagementError: "Key Management Error",
StatusConnectionAuthorizationRequired: "Connection Authorization Required",
StatusConnectionCredentialsNotAccepted: "Connection Credentials Not Accepted",
StatusFailureToEstablishSecureConnection: "Failure to Establish Secure Connection",
StatusInternalServerError: "Internal Server Error",
StatusNotImplemented: "Not Implemented",
StatusBadGateway: "Bad Gateway",
StatusServiceUnavailable: "Service Unavailable",
StatusGatewayTimeout: "Gateway Timeout",
StatusRTSPVersionNotSupported: "RTSP Version Not Supported",
StatusOptionNotSupported: "Option Not Supported",
StatusProxyUnavailable: "Proxy Unavailable",
}
// Response is a RTSP response.
type Response struct {
// numeric status code
StatusCode StatusCode
// status message
StatusMessage string
// map of header values
Header Header
// optional content
Content []byte
}
// ReadResponse reads a response from a buffered reader.
func ReadResponse(rb *bufio.Reader) (*Response, error) {
res := &Response{}
byts, err := readBytesLimited(rb, ' ', 255)
if err != nil {
return nil, err
}
proto := string(byts[:len(byts)-1])
if proto != rtspProtocol10 {
return nil, fmt.Errorf("expected '%s', got '%s'", rtspProtocol10, proto)
}
byts, err = readBytesLimited(rb, ' ', 4)
if err != nil {
return nil, err
}
statusCodeStr := string(byts[:len(byts)-1])
statusCode64, err := strconv.ParseInt(statusCodeStr, 10, 32)
if err != nil {
return nil, fmt.Errorf("unable to parse status code")
}
res.StatusCode = StatusCode(statusCode64)
byts, err = readBytesLimited(rb, '\r', 255)
if err != nil {
return nil, err
}
res.StatusMessage = string(byts[:len(byts)-1])
if len(res.StatusMessage) == 0 {
return nil, fmt.Errorf("empty status")
}
err = readByteEqual(rb, '\n')
if err != nil {
return nil, err
}
res.Header, err = headerRead(rb)
if err != nil {
return nil, err
}
res.Content, err = readContent(rb, res.Header)
if err != nil {
return nil, err
}
return res, nil
}
// Write writes a Response into a buffered writer.
func (res *Response) Write(bw *bufio.Writer) error {
if res.StatusMessage == "" {
if status, ok := statusMessages[res.StatusCode]; ok {
res.StatusMessage = status
}
}
_, err := bw.Write([]byte(rtspProtocol10 + " " + strconv.FormatInt(int64(res.StatusCode), 10) + " " + res.StatusMessage + "\r\n"))
if err != nil {
return err
}
if len(res.Content) != 0 {
res.Header["Content-Length"] = HeaderValue{strconv.FormatInt(int64(len(res.Content)), 10)}
}
err = res.Header.write(bw)
if err != nil {
return err
}
err = writeContent(bw, res.Content)
if err != nil {
return err
}
return bw.Flush()
}