123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262 |
- package local_http_proxy_server
- import (
- "encoding/base64"
- "fmt"
- "net"
- "net/http"
- "net/url"
- "sync"
- "time"
- "github.com/elazarl/goproxy"
- "golang.org/x/net/context"
- "golang.org/x/net/proxy"
- )
- // SetProxyInfo 设置代理信息,设置之前会停止现在运行的代理
- func SetProxyInfo(UseProxy bool, iInfos []string, iLocalPort string) error {
- locker.Lock()
- defer locker.Unlock()
- useProxy = UseProxy
- if localHttpProxyServer != nil && localHttpProxyServer.IsRunning() == true {
- // 需要关闭代理
- err := localHttpProxyServer.Stop()
- if err != nil {
- return err
- }
- }
- proxyInfos = iInfos
- localHttpProxyServerPort = iLocalPort
- return nil
- }
- // GetProxyUrl 获取代理地址,同时启动实例
- func GetProxyUrl() string {
- locker.Lock()
- defer locker.Unlock()
- if useProxy == false {
- if localHttpProxyServer != nil && localHttpProxyServer.IsRunning() == true {
- // 需要关闭代理
- err := localHttpProxyServer.Stop()
- if err != nil {
- println("localHttpProxyServer.Stop() Error:", err.Error())
- }
- }
- return ""
- }
- if localHttpProxyServer == nil {
- localHttpProxyServer = NewLocalHttpProxyServer()
- }
- if localHttpProxyServer.IsRunning() == true {
- return localHttpProxyServer.LocalHttpProxyUrl
- }
- localHttpProxyUrl, err := localHttpProxyServer.Start(proxyInfos, localHttpProxyServerPort)
- if err != nil {
- panic(fmt.Sprintln("start local http proxy server error:", err))
- return ""
- }
- return localHttpProxyUrl
- }
- // LocalHttpProxyServer see https://github.com/go-rod/rod/issues/305
- type LocalHttpProxyServer struct {
- srv *http.Server
- locker sync.Mutex
- isRunning bool
- LocalHttpProxyServerPort string // 本地开启的 Http 代理服务器端口
- LocalHttpProxyUrl string // 本地开启的 Http 代理服务器地址包含端口
- }
- func NewLocalHttpProxyServer() *LocalHttpProxyServer {
- return &LocalHttpProxyServer{}
- }
- func setBasicAuth(username, password string, req *http.Request) {
- req.Header.Set(ProxyAuthHeader, fmt.Sprintf("Basic %s", basicAuth(username, password)))
- }
- func basicAuth(username, password string) string {
- return base64.StdEncoding.EncodeToString([]byte(username + ":" + password))
- }
- // Start 传入参数为 [0] protocol [1] Address [2] Port [3] Username [4] Password,如果没得账号密码,则后面两个可以不传入
- func (l *LocalHttpProxyServer) Start(settings []string, localHttpProxyServerPort string) (string, error) {
- if len(settings) < 3 {
- return "", nil
- }
- l.LocalHttpProxyServerPort = localHttpProxyServerPort
- protocol := settings[0]
- InputProxyAddress := settings[1]
- InputProxyPort := settings[2]
- InputProxyUsername := ""
- InputProxyPassword := ""
- if len(settings) >= 5 {
- InputProxyUsername = settings[3]
- InputProxyPassword = settings[4]
- }
- proxyAddress := InputProxyAddress + ":" + InputProxyPort
- switch protocol {
- case "http":
- middleProxy := goproxy.NewProxyHttpServer()
- middleProxy.Tr.Proxy = func(req *http.Request) (*url.URL, error) {
- return url.Parse("http://" + proxyAddress)
- }
- //middleProxy.Logger = httpLogger()
- connectReqHandler := func(req *http.Request) {
- setBasicAuth(InputProxyUsername, InputProxyPassword, req)
- }
- middleProxy.ConnectDial = middleProxy.NewConnectDialToProxyWithHandler("http://"+proxyAddress, connectReqHandler)
- middleProxy.OnRequest().Do(goproxy.FuncReqHandler(func(req *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) {
- setBasicAuth(InputProxyUsername, InputProxyPassword, req)
- return req, nil
- }))
- l.srv = &http.Server{Addr: ":" + l.LocalHttpProxyServerPort, Handler: middleProxy}
- l.locker.Lock()
- l.isRunning = true
- l.locker.Unlock()
- go func() {
- println("Try Start Local Proxy Server at :", l.LocalHttpProxyServerPort)
- if err := l.srv.ListenAndServe(); err != http.ErrServerClosed {
- println(fmt.Sprintln("ListenAndServe() http proxy:", err))
- }
- l.locker.Lock()
- l.srv = nil
- l.isRunning = false
- l.LocalHttpProxyUrl = ""
- l.locker.Unlock()
- println("http proxy closed")
- }()
- time.Sleep(3 * time.Second)
- l.locker.Lock()
- l.LocalHttpProxyUrl = "http://127.0.0.1:" + l.LocalHttpProxyServerPort
- l.locker.Unlock()
- return l.LocalHttpProxyUrl, nil
- case "socks5":
- var dialer proxy.Dialer
- var err error
- if len(settings) >= 5 {
- auth := proxy.Auth{
- User: InputProxyUsername,
- Password: InputProxyPassword,
- }
- dialer, err = proxy.SOCKS5("tcp", proxyAddress, &auth, proxy.Direct)
- if err != nil {
- return "", err
- }
- } else {
- dialer, err = proxy.SOCKS5("tcp", proxyAddress, nil, proxy.Direct)
- if err != nil {
- return "", err
- }
- }
- dialContext := func(ctx context.Context, network, address string) (net.Conn, error) {
- return dialer.Dial(network, address)
- }
- dialContextOld := func(network, address string) (net.Conn, error) {
- return dialer.Dial(network, address)
- }
- transport := &http.Transport{DialContext: dialContext, DisableKeepAlives: true}
- middleProxy := goproxy.NewProxyHttpServer()
- middleProxy.Tr = transport
- //middleProxy.Logger = httpLogger()
- middleProxy.ConnectDial = dialContextOld
- middleProxy.OnRequest().Do(goproxy.FuncReqHandler(func(req *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) {
- setBasicAuth(InputProxyUsername, InputProxyPassword, req)
- return req, nil
- }))
- l.srv = &http.Server{Addr: ":" + l.LocalHttpProxyServerPort, Handler: middleProxy}
- l.locker.Lock()
- l.isRunning = true
- l.locker.Unlock()
- go func() {
- println("Try Start Local Proxy Server at :", l.LocalHttpProxyServerPort)
- if err := l.srv.ListenAndServe(); err != http.ErrServerClosed {
- println(fmt.Sprintln("ListenAndServe() socks5 proxy:", err))
- }
- l.locker.Lock()
- l.srv = nil
- l.isRunning = false
- l.LocalHttpProxyUrl = ""
- l.locker.Lock()
- println("socks5 proxy closed")
- }()
- time.Sleep(3 * time.Second)
- l.locker.Lock()
- l.LocalHttpProxyUrl = "http://127.0.0.1:" + l.LocalHttpProxyServerPort
- l.locker.Unlock()
- return l.LocalHttpProxyUrl, nil
- }
- return "", fmt.Errorf("proxy type invalid, not http or socks5")
- }
- func (l *LocalHttpProxyServer) Stop() error {
- if l.srv != nil {
- err := l.srv.Close()
- if err != nil {
- return err
- }
- }
- //
- //l.isRunning = false
- l.locker.Lock()
- l.LocalHttpProxyUrl = ""
- l.locker.Unlock()
- return nil
- }
- func (l *LocalHttpProxyServer) IsRunning() bool {
- l.locker.Lock()
- defer l.locker.Unlock()
- return l.isRunning
- }
- const (
- LocalHttpProxyPort = "19036"
- ProxyAuthHeader = "Proxy-Authorization"
- )
- var (
- locker sync.Mutex
- localHttpProxyServer *LocalHttpProxyServer
- useProxy bool
- proxyInfos = make([]string, 0)
- localHttpProxyServerPort string
- )
|