116 lines
2.3 KiB
Go
116 lines
2.3 KiB
Go
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]
|
|
}
|