You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
115 lines
2.3 KiB
115 lines
2.3 KiB
package websocket |
|
|
|
import ( |
|
"bytes" |
|
"fmt" |
|
"net/http" |
|
"strings" |
|
|
|
"go-common/app/service/main/broadcast/libs/bufio" |
|
) |
|
|
|
// Request request. |
|
type Request struct { |
|
Method string |
|
RequestURI string |
|
Proto string |
|
Host string |
|
Header http.Header |
|
|
|
reader *bufio.Reader |
|
} |
|
|
|
// ReadRequest reads and parses an incoming request from b. |
|
func ReadRequest(r *bufio.Reader) (req *Request, err error) { |
|
var ( |
|
b []byte |
|
ok bool |
|
) |
|
req = &Request{reader: r} |
|
if b, err = req.readLine(); err != nil { |
|
return |
|
} |
|
if req.Method, req.RequestURI, req.Proto, ok = parseRequestLine(string(b)); !ok { |
|
return nil, fmt.Errorf("malformed HTTP request %s", b) |
|
} |
|
if req.Header, err = req.readMIMEHeader(); err != nil { |
|
return |
|
} |
|
req.Host = req.Header.Get("Host") |
|
return req, nil |
|
} |
|
|
|
func (r *Request) readLine() ([]byte, error) { |
|
var line []byte |
|
for { |
|
l, more, err := r.reader.ReadLine() |
|
if err != nil { |
|
return nil, err |
|
} |
|
// Avoid the copy if the first call produced a full line. |
|
if line == nil && !more { |
|
return l, nil |
|
} |
|
line = append(line, l...) |
|
if !more { |
|
break |
|
} |
|
} |
|
return line, nil |
|
} |
|
|
|
func (r *Request) readMIMEHeader() (header http.Header, err error) { |
|
var ( |
|
line []byte |
|
i int |
|
k, v string |
|
) |
|
header = make(http.Header, 16) |
|
for { |
|
if line, err = r.readLine(); err != nil { |
|
return |
|
} |
|
line = trim(line) |
|
if len(line) == 0 { |
|
return |
|
} |
|
if i = bytes.IndexByte(line, ':'); i <= 0 { |
|
err = fmt.Errorf("malformed MIME header line: " + string(line)) |
|
return |
|
} |
|
k = string(line[:i]) |
|
// Skip initial spaces in value. |
|
i++ // skip colon |
|
for i < len(line) && (line[i] == ' ' || line[i] == '\t') { |
|
i++ |
|
} |
|
v = string(line[i:]) |
|
header.Add(k, v) |
|
} |
|
} |
|
|
|
// parseRequestLine parses "GET /foo HTTP/1.1" into its three parts. |
|
func parseRequestLine(line string) (method, requestURI, proto string, ok bool) { |
|
s1 := strings.Index(line, " ") |
|
s2 := strings.Index(line[s1+1:], " ") |
|
if s1 < 0 || s2 < 0 { |
|
return |
|
} |
|
s2 += s1 + 1 |
|
return line[:s1], line[s1+1 : s2], line[s2+1:], true |
|
} |
|
|
|
// trim returns s with leading and trailing spaces and tabs removed. |
|
// It does not assume Unicode or UTF-8. |
|
func trim(s []byte) []byte { |
|
i := 0 |
|
for i < len(s) && (s[i] == ' ' || s[i] == '\t') { |
|
i++ |
|
} |
|
n := len(s) |
|
for n > i && (s[n-1] == ' ' || s[n-1] == '\t') { |
|
n-- |
|
} |
|
return s[i:n] |
|
}
|
|
|