-
Notifications
You must be signed in to change notification settings - Fork 36
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #71 from SenseUnit/refactoring
Split packages
- Loading branch information
Showing
10 changed files
with
442 additions
and
421 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
package dialer | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"net" | ||
"net/url" | ||
"strings" | ||
"sync" | ||
|
||
xproxy "golang.org/x/net/proxy" | ||
) | ||
|
||
type Dialer = xproxy.Dialer | ||
type ContextDialer = xproxy.ContextDialer | ||
|
||
var registerDialerTypesOnce sync.Once | ||
|
||
func ProxyDialerFromURL(proxyURL string, forward Dialer) (Dialer, error) { | ||
registerDialerTypesOnce.Do(func() { | ||
xproxy.RegisterDialerType("http", HTTPProxyDialerFromURL) | ||
xproxy.RegisterDialerType("https", HTTPProxyDialerFromURL) | ||
}) | ||
parsedURL, err := url.Parse(proxyURL) | ||
if err != nil { | ||
return nil, fmt.Errorf("unable to parse proxy URL: %w", err) | ||
} | ||
d, err := xproxy.FromURL(parsedURL, forward) | ||
if err != nil { | ||
return nil, fmt.Errorf("unable to construct proxy dialer from URL %q: %w", proxyURL, err) | ||
} | ||
return d, nil | ||
} | ||
|
||
type wrappedDialer struct { | ||
d Dialer | ||
} | ||
|
||
func (wd wrappedDialer) Dial(net, address string) (net.Conn, error) { | ||
return wd.d.Dial(net, address) | ||
} | ||
|
||
func (wd wrappedDialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) { | ||
var ( | ||
conn net.Conn | ||
done = make(chan struct{}, 1) | ||
err error | ||
) | ||
go func() { | ||
conn, err = wd.d.Dial(network, address) | ||
close(done) | ||
if conn != nil && ctx.Err() != nil { | ||
conn.Close() | ||
} | ||
}() | ||
select { | ||
case <-ctx.Done(): | ||
err = ctx.Err() | ||
case <-done: | ||
} | ||
return conn, err | ||
} | ||
|
||
func MaybeWrapWithContextDialer(d Dialer) ContextDialer { | ||
if xd, ok := d.(ContextDialer); ok { | ||
return xd | ||
} | ||
return wrappedDialer{d} | ||
} | ||
|
||
func parseIPList(list string) ([]net.IP, error) { | ||
res := make([]net.IP, 0) | ||
for _, elem := range strings.Split(list, ",") { | ||
elem = strings.TrimSpace(elem) | ||
if len(elem) == 0 { | ||
continue | ||
} | ||
if parsed := net.ParseIP(elem); parsed == nil { | ||
return nil, fmt.Errorf("unable to parse IP address %q", elem) | ||
} else { | ||
res = append(res, parsed) | ||
} | ||
} | ||
return res, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
package main | ||
package dialer | ||
|
||
import ( | ||
"context" | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
package handler | ||
|
||
import ( | ||
"bufio" | ||
"context" | ||
"errors" | ||
"io" | ||
"net" | ||
"net/http" | ||
"sync" | ||
"time" | ||
) | ||
|
||
const COPY_BUF = 128 * 1024 | ||
|
||
func proxy(ctx context.Context, left, right net.Conn) { | ||
wg := sync.WaitGroup{} | ||
cpy := func(dst, src net.Conn) { | ||
defer wg.Done() | ||
io.Copy(dst, src) | ||
dst.Close() | ||
} | ||
wg.Add(2) | ||
go cpy(left, right) | ||
go cpy(right, left) | ||
groupdone := make(chan struct{}, 1) | ||
go func() { | ||
wg.Wait() | ||
groupdone <- struct{}{} | ||
}() | ||
select { | ||
case <-ctx.Done(): | ||
left.Close() | ||
right.Close() | ||
case <-groupdone: | ||
return | ||
} | ||
<-groupdone | ||
return | ||
} | ||
|
||
func proxyh2(ctx context.Context, leftreader io.ReadCloser, leftwriter io.Writer, right net.Conn) { | ||
wg := sync.WaitGroup{} | ||
ltr := func(dst net.Conn, src io.Reader) { | ||
defer wg.Done() | ||
io.Copy(dst, src) | ||
dst.Close() | ||
} | ||
rtl := func(dst io.Writer, src io.Reader) { | ||
defer wg.Done() | ||
copyBody(dst, src) | ||
} | ||
wg.Add(2) | ||
go ltr(right, leftreader) | ||
go rtl(leftwriter, right) | ||
groupdone := make(chan struct{}, 1) | ||
go func() { | ||
wg.Wait() | ||
groupdone <- struct{}{} | ||
}() | ||
select { | ||
case <-ctx.Done(): | ||
leftreader.Close() | ||
right.Close() | ||
case <-groupdone: | ||
return | ||
} | ||
<-groupdone | ||
return | ||
} | ||
|
||
// Hop-by-hop headers. These are removed when sent to the backend. | ||
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html | ||
var hopHeaders = []string{ | ||
"Connection", | ||
"Keep-Alive", | ||
"Proxy-Authenticate", | ||
"Proxy-Connection", | ||
"Proxy-Authorization", | ||
"Te", // canonicalized version of "TE" | ||
"Trailers", | ||
"Transfer-Encoding", | ||
"Upgrade", | ||
} | ||
|
||
func copyHeader(dst, src http.Header) { | ||
for k, vv := range src { | ||
for _, v := range vv { | ||
dst.Add(k, v) | ||
} | ||
} | ||
} | ||
|
||
func delHopHeaders(header http.Header) { | ||
for _, h := range hopHeaders { | ||
header.Del(h) | ||
} | ||
} | ||
|
||
func hijack(hijackable interface{}) (net.Conn, *bufio.ReadWriter, error) { | ||
hj, ok := hijackable.(http.Hijacker) | ||
if !ok { | ||
return nil, nil, errors.New("Connection doesn't support hijacking") | ||
} | ||
conn, rw, err := hj.Hijack() | ||
if err != nil { | ||
return nil, nil, err | ||
} | ||
var emptytime time.Time | ||
err = conn.SetDeadline(emptytime) | ||
if err != nil { | ||
conn.Close() | ||
return nil, nil, err | ||
} | ||
return conn, rw, nil | ||
} | ||
|
||
func flush(flusher interface{}) bool { | ||
f, ok := flusher.(http.Flusher) | ||
if !ok { | ||
return false | ||
} | ||
f.Flush() | ||
return true | ||
} | ||
|
||
func copyBody(wr io.Writer, body io.Reader) { | ||
buf := make([]byte, COPY_BUF) | ||
for { | ||
bread, read_err := body.Read(buf) | ||
var write_err error | ||
if bread > 0 { | ||
_, write_err = wr.Write(buf[:bread]) | ||
flush(wr) | ||
} | ||
if read_err != nil || write_err != nil { | ||
break | ||
} | ||
} | ||
} |
Oops, something went wrong.