lib/tunnel: use httputil.ReverseProxy
This commit is contained in:
parent
1e3765e37b
commit
48327a7669
|
@ -7,9 +7,12 @@ import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/http/httputil"
|
||||||
|
"net/url"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/koding/logging"
|
|
||||||
"git.xeserv.us/xena/route/lib/tunnel/proto"
|
"git.xeserv.us/xena/route/lib/tunnel/proto"
|
||||||
|
"github.com/koding/logging"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -29,9 +32,6 @@ type HTTPProxy struct {
|
||||||
// LocalAddr defines the TCP address of the local server.
|
// LocalAddr defines the TCP address of the local server.
|
||||||
// This is optional if you want to specify a single TCP address.
|
// This is optional if you want to specify a single TCP address.
|
||||||
LocalAddr string
|
LocalAddr string
|
||||||
// FetchLocalAddr is used for looking up TCP address of the server.
|
|
||||||
// This is optional if you want to specify a dynamic TCP address based on incommig port.
|
|
||||||
FetchLocalAddr func(port int) (string, error)
|
|
||||||
// ErrorResp is custom response send to tunnel server when client cannot
|
// ErrorResp is custom response send to tunnel server when client cannot
|
||||||
// establish connection to local server. If not set a default "no local server"
|
// establish connection to local server. If not set a default "no local server"
|
||||||
// response is sent.
|
// response is sent.
|
||||||
|
@ -39,6 +39,9 @@ type HTTPProxy struct {
|
||||||
// Log is a custom logger that can be used for the proxy.
|
// Log is a custom logger that can be used for the proxy.
|
||||||
// If not set a "http" logger is used.
|
// If not set a "http" logger is used.
|
||||||
Log logging.Logger
|
Log logging.Logger
|
||||||
|
|
||||||
|
hs *http.Server
|
||||||
|
rp *httputil.ReverseProxy
|
||||||
}
|
}
|
||||||
|
|
||||||
// Proxy is a ProxyFunc.
|
// Proxy is a ProxyFunc.
|
||||||
|
@ -57,25 +60,28 @@ func (p *HTTPProxy) Proxy(remote net.Conn, msg *proto.ControlMessage) {
|
||||||
var localAddr = fmt.Sprintf("127.0.0.1:%d", port)
|
var localAddr = fmt.Sprintf("127.0.0.1:%d", port)
|
||||||
if p.LocalAddr != "" {
|
if p.LocalAddr != "" {
|
||||||
localAddr = p.LocalAddr
|
localAddr = p.LocalAddr
|
||||||
} else if p.FetchLocalAddr != nil {
|
|
||||||
l, err := p.FetchLocalAddr(msg.LocalPort)
|
|
||||||
if err != nil {
|
|
||||||
log.Warning("Failed to get custom local address: %s", err)
|
|
||||||
p.sendError(remote)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
localAddr = l
|
|
||||||
|
if p.hs == nil {
|
||||||
|
su, _ := url.Parse(fmt.Sprintf("http://%s", p.LocalAddr))
|
||||||
|
p.rp = httputil.NewSingleHostReverseProxy(su)
|
||||||
|
p.hs = &http.Server{
|
||||||
|
Handler: p.rp,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debug("Dialing local server %q", localAddr)
|
log.Debug("Dialing local server %q", localAddr)
|
||||||
local, err := net.DialTimeout("tcp", localAddr, defaultTimeout)
|
|
||||||
|
sl := singleListener{
|
||||||
|
conn: remote,
|
||||||
|
}
|
||||||
|
|
||||||
|
err := p.hs.Serve(sl)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Dialing local server %q failed: %s", localAddr, err)
|
log.Error("Dialing local server %q failed: %s", localAddr, err)
|
||||||
p.sendError(remote)
|
p.sendError(remote)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
Join(local, remote, log)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *HTTPProxy) sendError(remote net.Conn) {
|
func (p *HTTPProxy) sendError(remote net.Conn) {
|
||||||
|
@ -113,3 +119,32 @@ func (p *HTTPProxy) log() logging.Logger {
|
||||||
}
|
}
|
||||||
return httpLog
|
return httpLog
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A singleListener is a net.Listener that returns a single connection, then
|
||||||
|
// gives the error io.EOF.
|
||||||
|
type singleListener struct {
|
||||||
|
conn net.Conn
|
||||||
|
once sync.Once
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s singleListener) Accept() (net.Conn, error) {
|
||||||
|
var c net.Conn
|
||||||
|
s.once.Do(func() {
|
||||||
|
c = s.conn
|
||||||
|
})
|
||||||
|
if c != nil {
|
||||||
|
return c, nil
|
||||||
|
}
|
||||||
|
return nil, io.EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s singleListener) Close() error {
|
||||||
|
s.once.Do(func() {
|
||||||
|
s.conn.Close()
|
||||||
|
})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s singleListener) Addr() net.Addr {
|
||||||
|
return s.conn.LocalAddr()
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue