-
Notifications
You must be signed in to change notification settings - Fork 1
/
request.go
131 lines (119 loc) · 2.73 KB
/
request.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
package rtsp
import (
"bufio"
"fmt"
"io"
"net/url"
"strconv"
"strings"
)
// RTSP Verbs
const (
MethodAnnounce = "ANNOUNCE"
MethodDescribe = "DESCRIBE"
MethodGetParameter = "GET_PARAMETER"
MethodOptions = "OPTIONS"
MethodPause = "PAUSE"
MethodPlay = "PLAY"
MethodRecord = "RECORD"
MethodRedirect = "REDIRECT"
MethodSetParameter = "SET_PARAMETER"
MethodSetup = "SETUP"
MethodTeardown = "TEARDOWN"
)
// Request contains all the information required to send a request
type Request struct {
Method string
URL *url.URL
Header Header
Body []byte
}
// Write the request to the provided writer in the wire format.
func (r Request) Write(w io.Writer) error {
if _, err := fmt.Fprintf(w, "%s %s %s\r\n", r.Method, r.URL, version); err != nil {
return err
}
if err := r.Header.Write(w); err != nil {
return err
}
if _, err := io.WriteString(w, "\r\n"); err != nil {
return err
}
if _, err := w.Write(r.Body); err != nil {
return err
}
return nil
}
// String returns a string representation of the request.
func (r Request) String() string {
var s strings.Builder
if err := r.Write(&s); err != nil {
return err.Error()
}
return s.String()
}
// NewRequest constructs a new request.
// The endpoint must be an absolute url.
// The body may be nil.
func NewRequest(method, endpoint string, body []byte) (*Request, error) {
u, err := url.Parse(endpoint)
if err != nil {
return nil, err
}
req := &Request{
Method: method,
URL: u,
Header: Header{},
Body: body,
}
if len(body) > 0 {
req.Header.Set("Content-Length", strconv.Itoa(len(body)))
}
return req, nil
}
// ReadRequest reads and parses an RTSP request from the provided reader.
func ReadRequest(r *bufio.Reader) (req *Request, err error) {
req = new(Request)
// read response line
var s string
if s, err = readLine(r); err != nil {
return
}
method, url, proto, ok := parseRequestLine(s)
if !ok {
return nil, fmt.Errorf("invalid request: %s", s)
}
if err := checkVersion(proto); err != nil {
return nil, err
}
req.Method = method
req.URL = url
// read headers
req.Header, err = ReadHeader(r)
if err != nil {
return
}
// read body
if cl := req.Header.Get("Content-Length"); cl != "" {
length, err := strconv.ParseInt(cl, 10, 64)
if err != nil {
return nil, fmt.Errorf("invalid Content-Length: %v", err)
}
req.Body = make([]byte, length)
if _, err := io.ReadFull(r, req.Body); err != nil {
return nil, err
}
}
return
}
func parseRequestLine(line string) (method string, uri *url.URL, proto string, ok bool) {
parts := strings.SplitN(line, " ", 3)
if len(parts) != 3 {
return
}
u, err := url.Parse(parts[1])
if err != nil {
return
}
return parts[0], u, parts[2], true
}