local_http_proxy_server.go 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. package local_http_proxy_server
  2. import (
  3. "encoding/base64"
  4. "fmt"
  5. "github.com/elazarl/goproxy"
  6. "golang.org/x/net/context"
  7. "golang.org/x/net/proxy"
  8. "net"
  9. "net/http"
  10. "net/url"
  11. )
  12. // LocalHttpProxyServer see https://github.com/go-rod/rod/issues/305
  13. type LocalHttpProxyServer struct {
  14. srv *http.Server
  15. isRunning bool
  16. LocalHttpProxyServerPort string // 本地开启的 Http 代理服务器端口
  17. LocalHttpProxyUrl string // 本地开启的 Http 代理服务器地址包含端口
  18. }
  19. func NewLocalHttpProxyServer() *LocalHttpProxyServer {
  20. return &LocalHttpProxyServer{}
  21. }
  22. func setBasicAuth(username, password string, req *http.Request) {
  23. req.Header.Set(ProxyAuthHeader, fmt.Sprintf("Basic %s", basicAuth(username, password)))
  24. }
  25. func basicAuth(username, password string) string {
  26. return base64.StdEncoding.EncodeToString([]byte(username + ":" + password))
  27. }
  28. // Start 传入参数为 [0] protocol [1] Address [2] Port [3] Username [4] Password,如果没得账号密码,则后面两个可以不传入
  29. func (l *LocalHttpProxyServer) Start(settings []string, localHttpProxyServerPort string) (string, error) {
  30. if len(settings) < 3 {
  31. return "", nil
  32. }
  33. l.LocalHttpProxyServerPort = localHttpProxyServerPort
  34. protocol := settings[0]
  35. InputProxyAddress := settings[1]
  36. InputProxyPort := settings[2]
  37. InputProxyUsername := ""
  38. InputProxyPassword := ""
  39. if len(settings) >= 5 {
  40. InputProxyUsername = settings[3]
  41. InputProxyPassword = settings[4]
  42. }
  43. proxyAddress := InputProxyAddress + ":" + InputProxyPort
  44. switch protocol {
  45. case "http":
  46. middleProxy := goproxy.NewProxyHttpServer()
  47. middleProxy.Tr.Proxy = func(req *http.Request) (*url.URL, error) {
  48. return url.Parse("http://" + proxyAddress)
  49. }
  50. //middleProxy.Logger = httpLogger()
  51. connectReqHandler := func(req *http.Request) {
  52. setBasicAuth(InputProxyUsername, InputProxyPassword, req)
  53. }
  54. middleProxy.ConnectDial = middleProxy.NewConnectDialToProxyWithHandler("http://"+proxyAddress, connectReqHandler)
  55. middleProxy.OnRequest().Do(goproxy.FuncReqHandler(func(req *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) {
  56. setBasicAuth(InputProxyUsername, InputProxyPassword, req)
  57. return req, nil
  58. }))
  59. l.srv = &http.Server{Addr: ":" + l.LocalHttpProxyServerPort, Handler: middleProxy}
  60. go func() {
  61. if err := l.srv.ListenAndServe(); err != http.ErrServerClosed {
  62. panic(fmt.Sprintln("ListenAndServe() http proxy:", err))
  63. }
  64. }()
  65. l.isRunning = true
  66. l.LocalHttpProxyUrl = "http://127.0.0.1:" + l.LocalHttpProxyServerPort
  67. return l.LocalHttpProxyUrl, nil
  68. case "socks5":
  69. var dialer proxy.Dialer
  70. var err error
  71. if len(settings) >= 5 {
  72. auth := proxy.Auth{
  73. User: InputProxyUsername,
  74. Password: InputProxyPassword,
  75. }
  76. dialer, err = proxy.SOCKS5("tcp", proxyAddress, &auth, proxy.Direct)
  77. if err != nil {
  78. return "", err
  79. }
  80. } else {
  81. dialer, err = proxy.SOCKS5("tcp", proxyAddress, nil, proxy.Direct)
  82. if err != nil {
  83. return "", err
  84. }
  85. }
  86. dialContext := func(ctx context.Context, network, address string) (net.Conn, error) {
  87. return dialer.Dial(network, address)
  88. }
  89. dialContextOld := func(network, address string) (net.Conn, error) {
  90. return dialer.Dial(network, address)
  91. }
  92. transport := &http.Transport{DialContext: dialContext, DisableKeepAlives: true}
  93. middleProxy := goproxy.NewProxyHttpServer()
  94. middleProxy.Tr = transport
  95. //middleProxy.Logger = httpLogger()
  96. middleProxy.ConnectDial = dialContextOld
  97. middleProxy.OnRequest().Do(goproxy.FuncReqHandler(func(req *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) {
  98. setBasicAuth(InputProxyUsername, InputProxyPassword, req)
  99. return req, nil
  100. }))
  101. l.srv = &http.Server{Addr: ":" + l.LocalHttpProxyServerPort, Handler: middleProxy}
  102. go func() {
  103. if err := l.srv.ListenAndServe(); err != http.ErrServerClosed {
  104. panic(fmt.Sprintln("ListenAndServe() socks5 proxy:", err))
  105. }
  106. }()
  107. l.isRunning = true
  108. l.LocalHttpProxyUrl = "http://127.0.0.1:" + l.LocalHttpProxyServerPort
  109. return l.LocalHttpProxyUrl, nil
  110. }
  111. return "", fmt.Errorf("proxy type invalid, not http or socks5")
  112. }
  113. func (l *LocalHttpProxyServer) Stop() error {
  114. if l.srv != nil {
  115. err := l.srv.Close()
  116. if err != nil {
  117. return err
  118. }
  119. }
  120. l.srv = nil
  121. l.isRunning = false
  122. l.LocalHttpProxyUrl = ""
  123. return nil
  124. }
  125. func (l *LocalHttpProxyServer) IsRunning() bool {
  126. return l.isRunning
  127. }
  128. const (
  129. LocalHttpProxyPort = "19036"
  130. ProxyAuthHeader = "Proxy-Authorization"
  131. )