glider/proxy/http/request.go
2019-10-21 15:44:50 +08:00

117 lines
2.1 KiB
Go

package http
import (
"bufio"
"bytes"
"errors"
"net/textproto"
"net/url"
"strings"
"github.com/nadoo/glider/common/log"
)
// Methods are http methods from rfc.
// https://www.ietf.org/rfc/rfc2616.txt, http methods must be uppercase
var Methods = [...][]byte{
[]byte("GET"),
[]byte("POST"),
[]byte("PUT"),
[]byte("DELETE"),
[]byte("CONNECT"),
[]byte("HEAD"),
[]byte("OPTIONS"),
[]byte("TRACE"),
[]byte("PATCH"),
}
type request struct {
method string
uri string
proto string
auth string
header textproto.MIMEHeader
target string // target host with port
ruri string // relative uri
absuri string // absolute uri
}
func parseRequest(r *bufio.Reader) (*request, error) {
tpr := textproto.NewReader(r)
line, err := tpr.ReadLine()
if err != nil {
return nil, err
}
method, uri, proto, ok := parseStartLine(line)
if !ok {
return nil, errors.New("error in parseStartLine")
}
header, err := tpr.ReadMIMEHeader()
if err != nil {
log.F("[http] read header error:%s", err)
return nil, err
}
log.F("req header: %v", header)
auth := header.Get("Proxy-Authorization")
cleanHeaders(header)
header.Set("Connection", "close")
u, err := url.ParseRequestURI(uri)
if err != nil {
log.F("[http] parse request url error: %s, uri: %s", err, uri)
return nil, err
}
var tgt = u.Host
if !strings.Contains(u.Host, ":") {
tgt += ":80"
}
req := &request{
method: method,
uri: uri,
proto: proto,
auth: auth,
header: header,
target: tgt,
}
if u.IsAbs() {
req.absuri = u.String()
u.Scheme = ""
u.Host = ""
req.ruri = u.String()
} else {
req.ruri = u.String()
base, err := url.Parse("http://" + header.Get("Host"))
if err != nil {
return nil, err
}
u = base.ResolveReference(u)
req.absuri = u.String()
}
return req, nil
}
func (r *request) Marshal() []byte {
var buf bytes.Buffer
writeStartLine(&buf, r.method, r.ruri, r.proto)
writeHeaders(&buf, r.header)
return buf.Bytes()
}
func (r *request) MarshalAbs() []byte {
var buf bytes.Buffer
writeStartLine(&buf, r.method, r.absuri, r.proto)
writeHeaders(&buf, r.header)
return buf.Bytes()
}