http_proxy: fix error using encryption or compression

This commit is contained in:
fatedier 2017-06-09 02:13:24 +08:00
parent 70e2aee46d
commit 2a044c9d6d
1 changed files with 62 additions and 6 deletions

View File

@ -15,6 +15,7 @@
package plugin
import (
"bufio"
"encoding/base64"
"fmt"
"io"
@ -106,14 +107,26 @@ func (hp *HttpProxy) Name() string {
}
func (hp *HttpProxy) Handle(conn io.ReadWriteCloser) {
var wrapConn net.Conn
if realConn, ok := conn.(net.Conn); ok {
var wrapConn frpNet.Conn
if realConn, ok := conn.(frpNet.Conn); ok {
wrapConn = realConn
} else {
wrapConn = frpNet.WrapReadWriteCloserToConn(conn)
}
hp.l.PutConn(wrapConn)
sc, rd := frpNet.NewShareConn(wrapConn)
request, err := http.ReadRequest(bufio.NewReader(rd))
if err != nil {
wrapConn.Close()
return
}
if request.Method == http.MethodConnect {
hp.handleConnectReq(request, frpIo.WrapReadWriteCloser(rd, wrapConn, nil))
return
}
hp.l.PutConn(sc)
return
}
@ -124,13 +137,15 @@ func (hp *HttpProxy) Close() error {
}
func (hp *HttpProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
if ok := hp.Auth(rw, req); !ok {
if ok := hp.Auth(req); !ok {
rw.Header().Set("Proxy-Authenticate", "Basic")
rw.WriteHeader(http.StatusProxyAuthRequired)
return
}
if req.Method == "CONNECT" {
if req.Method == http.MethodConnect {
// deprecated
// Connect request is handled in Handle function.
hp.ConnectHandler(rw, req)
} else {
hp.HttpHandler(rw, req)
@ -156,6 +171,9 @@ func (hp *HttpProxy) HttpHandler(rw http.ResponseWriter, req *http.Request) {
}
}
// deprecated
// Hijack needs to SetReadDeadline on the Conn of the request, but if we use stream compression here,
// we may always get i/o timeout error.
func (hp *HttpProxy) ConnectHandler(rw http.ResponseWriter, req *http.Request) {
hj, ok := rw.(http.Hijacker)
if !ok {
@ -180,7 +198,7 @@ func (hp *HttpProxy) ConnectHandler(rw http.ResponseWriter, req *http.Request) {
go frpIo.Join(remote, client)
}
func (hp *HttpProxy) Auth(rw http.ResponseWriter, req *http.Request) bool {
func (hp *HttpProxy) Auth(req *http.Request) bool {
if hp.AuthUser == "" && hp.AuthPasswd == "" {
return true
}
@ -206,6 +224,30 @@ func (hp *HttpProxy) Auth(rw http.ResponseWriter, req *http.Request) bool {
return true
}
func (hp *HttpProxy) handleConnectReq(req *http.Request, rwc io.ReadWriteCloser) {
defer rwc.Close()
if ok := hp.Auth(req); !ok {
res := getBadResponse()
res.Write(rwc)
return
}
remote, err := net.Dial("tcp", req.URL.Host)
if err != nil {
res := &http.Response{
StatusCode: 400,
Proto: "HTTP/1.1",
ProtoMajor: 1,
ProtoMinor: 1,
}
res.Write(rwc)
return
}
rwc.Write([]byte("HTTP/1.1 200 OK\r\n\r\n"))
frpIo.Join(remote, rwc)
}
func copyHeaders(dst, src http.Header) {
for key, values := range src {
for _, value := range values {
@ -225,3 +267,17 @@ func removeProxyHeaders(req *http.Request) {
req.Header.Del("Transfer-Encoding")
req.Header.Del("Upgrade")
}
func getBadResponse() *http.Response {
header := make(map[string][]string)
header["Proxy-Authenticate"] = []string{"Basic"}
res := &http.Response{
Status: "407 Not authorized",
StatusCode: 407,
Proto: "HTTP/1.1",
ProtoMajor: 1,
ProtoMinor: 1,
Header: header,
}
return res
}