2019-04-22 02:59:20 +00:00

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]
}