mirror of https://github.com/ginuerzh/gost
8 changed files with 249 additions and 41 deletions
@ -0,0 +1,127 @@ |
|||||
|
package gost |
||||
|
|
||||
|
import ( |
||||
|
"bufio" |
||||
|
"bytes" |
||||
|
"crypto/rand" |
||||
|
"io" |
||||
|
"io/ioutil" |
||||
|
"net/http" |
||||
|
"net/http/httptest" |
||||
|
"net/url" |
||||
|
"testing" |
||||
|
) |
||||
|
|
||||
|
var httpTestHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
||||
|
io.Copy(w, r.Body) |
||||
|
}) |
||||
|
|
||||
|
func httpProxyRoundtrip(urlStr string, cliUser *url.Userinfo, srvUsers []*url.Userinfo, body io.Reader) (statusCode int, recv []byte, err error) { |
||||
|
ln, err := TCPListener("") |
||||
|
if err != nil { |
||||
|
return |
||||
|
} |
||||
|
h := HTTPHandler(UsersHandlerOption(srvUsers...)) |
||||
|
server := &Server{Listener: ln} |
||||
|
go server.Serve(h) |
||||
|
|
||||
|
exitChan := make(chan struct{}) |
||||
|
defer close(exitChan) |
||||
|
go func() { |
||||
|
defer server.Close() |
||||
|
<-exitChan |
||||
|
}() |
||||
|
|
||||
|
client := &Client{ |
||||
|
Connector: HTTPConnector(cliUser), |
||||
|
Transporter: TCPTransporter(), |
||||
|
} |
||||
|
conn, err := client.Dial(ln.Addr().String()) |
||||
|
if err != nil { |
||||
|
return |
||||
|
} |
||||
|
defer conn.Close() |
||||
|
conn, err = client.Handshake(conn) |
||||
|
if err != nil { |
||||
|
return |
||||
|
} |
||||
|
url, err := url.Parse(urlStr) |
||||
|
if err != nil { |
||||
|
return |
||||
|
} |
||||
|
conn, err = client.Connect(conn, url.Host) |
||||
|
if err != nil { |
||||
|
return |
||||
|
} |
||||
|
req, err := http.NewRequest(http.MethodGet, urlStr, body) |
||||
|
if err != nil { |
||||
|
return |
||||
|
} |
||||
|
if err = req.Write(conn); err != nil { |
||||
|
return |
||||
|
} |
||||
|
resp, err := http.ReadResponse(bufio.NewReader(conn), req) |
||||
|
if err != nil { |
||||
|
return |
||||
|
} |
||||
|
defer resp.Body.Close() |
||||
|
statusCode = resp.StatusCode |
||||
|
recv, err = ioutil.ReadAll(resp.Body) |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
var httpProxyTests = []struct { |
||||
|
url string |
||||
|
cliUser *url.Userinfo |
||||
|
srvUsers []*url.Userinfo |
||||
|
errStr string |
||||
|
}{ |
||||
|
{"", nil, nil, ""}, |
||||
|
{"", nil, []*url.Userinfo{url.User("admin")}, "407 Proxy Authentication Required"}, |
||||
|
{"", nil, []*url.Userinfo{url.UserPassword("", "123456")}, "407 Proxy Authentication Required"}, |
||||
|
{"", url.User("admin"), []*url.Userinfo{url.User("test")}, "407 Proxy Authentication Required"}, |
||||
|
{"", url.User("admin"), []*url.Userinfo{url.UserPassword("admin", "123456")}, "407 Proxy Authentication Required"}, |
||||
|
{"", url.User("admin"), []*url.Userinfo{url.User("admin")}, ""}, |
||||
|
{"", url.User("admin"), []*url.Userinfo{url.UserPassword("admin", "")}, ""}, |
||||
|
{"", url.UserPassword("admin", "123456"), nil, ""}, |
||||
|
{"", url.UserPassword("admin", "123456"), []*url.Userinfo{url.User("admin")}, ""}, |
||||
|
{"", url.UserPassword("admin", "123456"), []*url.Userinfo{url.UserPassword("", "123456")}, ""}, |
||||
|
{"", url.UserPassword("", "123456"), []*url.Userinfo{url.UserPassword("", "123456")}, ""}, |
||||
|
{"", url.UserPassword("admin", "123456"), []*url.Userinfo{url.UserPassword("admin", "123456")}, ""}, |
||||
|
{"", url.UserPassword("admin", "123456"), []*url.Userinfo{url.UserPassword("user", "pass"), url.UserPassword("admin", "123456")}, ""}, |
||||
|
{"http://:0", nil, nil, "503 Service unavailable"}, |
||||
|
} |
||||
|
|
||||
|
func TestHTTPProxy(t *testing.T) { |
||||
|
Debug = true |
||||
|
httpSrv := httptest.NewServer(httpTestHandler) |
||||
|
defer httpSrv.Close() |
||||
|
|
||||
|
for _, test := range httpProxyTests { |
||||
|
send := make([]byte, 16) |
||||
|
rand.Read(send) |
||||
|
urlStr := test.url |
||||
|
if urlStr == "" { |
||||
|
urlStr = httpSrv.URL |
||||
|
} |
||||
|
_, recv, err := httpProxyRoundtrip(urlStr, test.cliUser, test.srvUsers, bytes.NewReader(send)) |
||||
|
if err == nil { |
||||
|
if test.errStr != "" { |
||||
|
t.Errorf("HTTP proxy response should failed with error %s", test.errStr) |
||||
|
continue |
||||
|
} |
||||
|
} else { |
||||
|
if test.errStr == "" { |
||||
|
t.Errorf("HTTP proxy got error %v", err) |
||||
|
} |
||||
|
if err.Error() != test.errStr { |
||||
|
t.Errorf("HTTP proxy got error %v, want %v", err, test.errStr) |
||||
|
} |
||||
|
continue |
||||
|
} |
||||
|
if !bytes.Equal(send, recv) { |
||||
|
t.Errorf("got %v, want %v", recv, send) |
||||
|
continue |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,68 @@ |
|||||
|
package gost |
||||
|
|
||||
|
import "testing" |
||||
|
import "net/url" |
||||
|
|
||||
|
var nodeTests = []struct { |
||||
|
in string |
||||
|
out Node |
||||
|
hasError bool |
||||
|
}{ |
||||
|
{"", Node{}, false}, |
||||
|
{"://", Node{}, true}, |
||||
|
{"localhost", Node{Addr: "localhost", Transport: "tcp"}, false}, |
||||
|
{":", Node{Addr: ":", Transport: "tcp"}, false}, |
||||
|
{":8080", Node{Addr: ":8080", Transport: "tcp"}, false}, |
||||
|
{"http://:8080", Node{Addr: ":8080", Protocol: "http", Transport: "tcp"}, false}, |
||||
|
{"http://localhost:8080", Node{Addr: "localhost:8080", Protocol: "http", Transport: "tcp"}, false}, |
||||
|
{"http://admin:123456@:8080", Node{Addr: ":8080", Protocol: "http", Transport: "tcp", User: url.UserPassword("admin", "123456")}, false}, |
||||
|
{"http://admin@localhost:8080", Node{Addr: "localhost:8080", Protocol: "http", Transport: "tcp", User: url.User("admin")}, false}, |
||||
|
{"http://:123456@localhost:8080", Node{Addr: "localhost:8080", Protocol: "http", Transport: "tcp", User: url.UserPassword("", "123456")}, false}, |
||||
|
{"http://@localhost:8080", Node{Addr: "localhost:8080", Protocol: "http", Transport: "tcp", User: url.User("")}, false}, |
||||
|
{"http://:@localhost:8080", Node{Addr: "localhost:8080", Protocol: "http", Transport: "tcp", User: url.UserPassword("", "")}, false}, |
||||
|
{"https://:8080", Node{Addr: ":8080", Protocol: "http", Transport: "tls"}, false}, |
||||
|
{"socks+tls://:8080", Node{Addr: ":8080", Protocol: "socks5", Transport: "tls"}, false}, |
||||
|
{"tls://:8080", Node{Addr: ":8080", Transport: "tls"}, false}, |
||||
|
{"tcp://:8080/:8081", Node{Addr: ":8080", Remote: ":8081", Protocol: "tcp", Transport: "tcp"}, false}, |
||||
|
{"udp://:8080/:8081", Node{Addr: ":8080", Remote: ":8081", Protocol: "udp", Transport: "udp"}, false}, |
||||
|
{"rtcp://:8080/:8081", Node{Addr: ":8080", Remote: ":8081", Protocol: "rtcp", Transport: "rtcp"}, false}, |
||||
|
{"rudp://:8080/:8081", Node{Addr: ":8080", Remote: ":8081", Protocol: "rudp", Transport: "rudp"}, false}, |
||||
|
{"redirect://:8080", Node{Addr: ":8080", Protocol: "redirect", Transport: "tcp"}, false}, |
||||
|
} |
||||
|
|
||||
|
func TestParseNode(t *testing.T) { |
||||
|
for _, test := range nodeTests { |
||||
|
actual, err := ParseNode(test.in) |
||||
|
if err != nil { |
||||
|
if test.hasError { |
||||
|
t.Logf("ParseNode(%q) got expected error: %v", test.in, err) |
||||
|
continue |
||||
|
} |
||||
|
t.Errorf("ParseNode(%q) got error: %v", test.in, err) |
||||
|
} else { |
||||
|
if test.hasError { |
||||
|
t.Errorf("ParseNode(%q) got %v, but should return error", test.in, actual) |
||||
|
continue |
||||
|
} |
||||
|
if actual.Addr != test.out.Addr || actual.Protocol != test.out.Protocol || |
||||
|
actual.Transport != test.out.Transport || actual.Remote != test.out.Remote { |
||||
|
t.Errorf("ParseNode(%q) got %v, want %v", test.in, actual, test.out) |
||||
|
} |
||||
|
if actual.User == nil { |
||||
|
if test.out.User != nil { |
||||
|
t.Errorf("ParseNode(%q) got %v, want %v", test.in, actual, test.out) |
||||
|
} |
||||
|
continue |
||||
|
} |
||||
|
if actual.User != nil { |
||||
|
if test.out.User == nil { |
||||
|
t.Errorf("ParseNode(%q) got %v, want %v", test.in, actual, test.out) |
||||
|
continue |
||||
|
} |
||||
|
if *actual.User != *test.out.User { |
||||
|
t.Errorf("ParseNode(%q) got %v, want %v", test.in, actual, test.out) |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue