local_http_proxy_server.go 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. package local_http_proxy_server
  2. import (
  3. "encoding/base64"
  4. "fmt"
  5. "net"
  6. "net/http"
  7. "net/url"
  8. "sync"
  9. "time"
  10. "github.com/elazarl/goproxy"
  11. "golang.org/x/net/context"
  12. "golang.org/x/net/proxy"
  13. )
  14. // SetProxyInfo 设置代理信息,设置之前会停止现在运行的代理
  15. func SetProxyInfo(UseProxy bool, iInfos []string, iLocalPort string) error {
  16. locker.Lock()
  17. defer locker.Unlock()
  18. useProxy = UseProxy
  19. if localHttpProxyServer != nil && localHttpProxyServer.IsRunning() == true {
  20. // 需要关闭代理
  21. err := localHttpProxyServer.Stop()
  22. if err != nil {
  23. return err
  24. }
  25. }
  26. proxyInfos = iInfos
  27. localHttpProxyServerPort = iLocalPort
  28. return nil
  29. }
  30. // GetProxyUrl 获取代理地址,同时启动实例
  31. func GetProxyUrl() string {
  32. locker.Lock()
  33. defer locker.Unlock()
  34. if useProxy == false {
  35. if localHttpProxyServer != nil && localHttpProxyServer.IsRunning() == true {
  36. // 需要关闭代理
  37. err := localHttpProxyServer.Stop()
  38. if err != nil {
  39. println("localHttpProxyServer.Stop() Error:", err.Error())
  40. }
  41. }
  42. return ""
  43. }
  44. if localHttpProxyServer == nil {
  45. localHttpProxyServer = NewLocalHttpProxyServer()
  46. }
  47. if localHttpProxyServer.IsRunning() == true {
  48. return localHttpProxyServer.LocalHttpProxyUrl
  49. }
  50. localHttpProxyUrl, err := localHttpProxyServer.Start(proxyInfos, localHttpProxyServerPort)
  51. if err != nil {
  52. panic(fmt.Sprintln("start local http proxy server error:", err))
  53. return ""
  54. }
  55. return localHttpProxyUrl
  56. }
  57. // LocalHttpProxyServer see https://github.com/go-rod/rod/issues/305
  58. type LocalHttpProxyServer struct {
  59. srv *http.Server
  60. locker sync.Mutex
  61. isRunning bool
  62. LocalHttpProxyServerPort string // 本地开启的 Http 代理服务器端口
  63. LocalHttpProxyUrl string // 本地开启的 Http 代理服务器地址包含端口
  64. }
  65. func NewLocalHttpProxyServer() *LocalHttpProxyServer {
  66. return &LocalHttpProxyServer{}
  67. }
  68. func setBasicAuth(username, password string, req *http.Request) {
  69. req.Header.Set(ProxyAuthHeader, fmt.Sprintf("Basic %s", basicAuth(username, password)))
  70. }
  71. func basicAuth(username, password string) string {
  72. return base64.StdEncoding.EncodeToString([]byte(username + ":" + password))
  73. }
  74. // Start 传入参数为 [0] protocol [1] Address [2] Port [3] Username [4] Password,如果没得账号密码,则后面两个可以不传入
  75. func (l *LocalHttpProxyServer) Start(settings []string, localHttpProxyServerPort string) (string, error) {
  76. if len(settings) < 3 {
  77. return "", nil
  78. }
  79. l.LocalHttpProxyServerPort = localHttpProxyServerPort
  80. protocol := settings[0]
  81. InputProxyAddress := settings[1]
  82. InputProxyPort := settings[2]
  83. InputProxyUsername := ""
  84. InputProxyPassword := ""
  85. if len(settings) >= 5 {
  86. InputProxyUsername = settings[3]
  87. InputProxyPassword = settings[4]
  88. }
  89. proxyAddress := InputProxyAddress + ":" + InputProxyPort
  90. switch protocol {
  91. case "http":
  92. middleProxy := goproxy.NewProxyHttpServer()
  93. middleProxy.Tr.Proxy = func(req *http.Request) (*url.URL, error) {
  94. return url.Parse("http://" + proxyAddress)
  95. }
  96. //middleProxy.Logger = httpLogger()
  97. connectReqHandler := func(req *http.Request) {
  98. setBasicAuth(InputProxyUsername, InputProxyPassword, req)
  99. }
  100. middleProxy.ConnectDial = middleProxy.NewConnectDialToProxyWithHandler("http://"+proxyAddress, connectReqHandler)
  101. middleProxy.OnRequest().Do(goproxy.FuncReqHandler(func(req *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) {
  102. setBasicAuth(InputProxyUsername, InputProxyPassword, req)
  103. return req, nil
  104. }))
  105. l.srv = &http.Server{Addr: ":" + l.LocalHttpProxyServerPort, Handler: middleProxy}
  106. l.locker.Lock()
  107. l.isRunning = true
  108. l.locker.Unlock()
  109. go func() {
  110. println("Try Start Local Proxy Server at :", l.LocalHttpProxyServerPort)
  111. if err := l.srv.ListenAndServe(); err != http.ErrServerClosed {
  112. println(fmt.Sprintln("ListenAndServe() http proxy:", err))
  113. }
  114. l.locker.Lock()
  115. l.srv = nil
  116. l.isRunning = false
  117. l.LocalHttpProxyUrl = ""
  118. l.locker.Unlock()
  119. println("http proxy closed")
  120. }()
  121. time.Sleep(3 * time.Second)
  122. l.locker.Lock()
  123. l.LocalHttpProxyUrl = "http://127.0.0.1:" + l.LocalHttpProxyServerPort
  124. l.locker.Unlock()
  125. return l.LocalHttpProxyUrl, nil
  126. case "socks5":
  127. var dialer proxy.Dialer
  128. var err error
  129. if len(settings) >= 5 {
  130. auth := proxy.Auth{
  131. User: InputProxyUsername,
  132. Password: InputProxyPassword,
  133. }
  134. dialer, err = proxy.SOCKS5("tcp", proxyAddress, &auth, proxy.Direct)
  135. if err != nil {
  136. return "", err
  137. }
  138. } else {
  139. dialer, err = proxy.SOCKS5("tcp", proxyAddress, nil, proxy.Direct)
  140. if err != nil {
  141. return "", err
  142. }
  143. }
  144. dialContext := func(ctx context.Context, network, address string) (net.Conn, error) {
  145. return dialer.Dial(network, address)
  146. }
  147. dialContextOld := func(network, address string) (net.Conn, error) {
  148. return dialer.Dial(network, address)
  149. }
  150. transport := &http.Transport{DialContext: dialContext, DisableKeepAlives: true}
  151. middleProxy := goproxy.NewProxyHttpServer()
  152. middleProxy.Tr = transport
  153. //middleProxy.Logger = httpLogger()
  154. middleProxy.ConnectDial = dialContextOld
  155. middleProxy.OnRequest().Do(goproxy.FuncReqHandler(func(req *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) {
  156. setBasicAuth(InputProxyUsername, InputProxyPassword, req)
  157. return req, nil
  158. }))
  159. l.srv = &http.Server{Addr: ":" + l.LocalHttpProxyServerPort, Handler: middleProxy}
  160. l.locker.Lock()
  161. l.isRunning = true
  162. l.locker.Unlock()
  163. go func() {
  164. println("Try Start Local Proxy Server at :", l.LocalHttpProxyServerPort)
  165. if err := l.srv.ListenAndServe(); err != http.ErrServerClosed {
  166. println(fmt.Sprintln("ListenAndServe() socks5 proxy:", err))
  167. }
  168. l.locker.Lock()
  169. l.srv = nil
  170. l.isRunning = false
  171. l.LocalHttpProxyUrl = ""
  172. l.locker.Lock()
  173. println("socks5 proxy closed")
  174. }()
  175. time.Sleep(3 * time.Second)
  176. l.locker.Lock()
  177. l.LocalHttpProxyUrl = "http://127.0.0.1:" + l.LocalHttpProxyServerPort
  178. l.locker.Unlock()
  179. return l.LocalHttpProxyUrl, nil
  180. }
  181. return "", fmt.Errorf("proxy type invalid, not http or socks5")
  182. }
  183. func (l *LocalHttpProxyServer) Stop() error {
  184. if l.srv != nil {
  185. err := l.srv.Close()
  186. if err != nil {
  187. return err
  188. }
  189. }
  190. //
  191. //l.isRunning = false
  192. l.locker.Lock()
  193. l.LocalHttpProxyUrl = ""
  194. l.locker.Unlock()
  195. return nil
  196. }
  197. func (l *LocalHttpProxyServer) IsRunning() bool {
  198. l.locker.Lock()
  199. defer l.locker.Unlock()
  200. return l.isRunning
  201. }
  202. const (
  203. LocalHttpProxyPort = "19036"
  204. ProxyAuthHeader = "Proxy-Authorization"
  205. )
  206. var (
  207. locker sync.Mutex
  208. localHttpProxyServer *LocalHttpProxyServer
  209. useProxy bool
  210. proxyInfos = make([]string, 0)
  211. localHttpProxyServerPort string
  212. )