mirror of
https://github.com/valyala/fasthttp.git
synced 2026-06-24 17:35:53 +03:00
ea6052464e
* Update Go Version to Go1.19.x And add cache * Fix CI Line endings * Update test CI Go Version to Go1.19.x And add cache * Update Gosec Security Scanner CI to securego/gosec@v2.12.0 * Format comment Go 1.19 adds support for links, lists, and clearer headings in doc comments. As part of this change, gofmt now reformats doc comments to make their rendered meaning clearer. See “Go Doc Comments” for syntax details and descriptions of common mistakes now highlighted by gofmt. As another part of this change, the new package go/doc/comment provides parsing and reformatting of doc comments as well as support for rendering them to HTML, Markdown, and text. ref: https://tip.golang.org/doc/go1.19 ref: https://tip.golang.org/doc/comment * Fix doc structure
128 lines
3.0 KiB
Go
128 lines
3.0 KiB
Go
package fasthttpproxy
|
|
|
|
import (
|
|
"bufio"
|
|
"encoding/base64"
|
|
"fmt"
|
|
"net"
|
|
"net/url"
|
|
"sync/atomic"
|
|
"time"
|
|
|
|
"golang.org/x/net/http/httpproxy"
|
|
|
|
"github.com/valyala/fasthttp"
|
|
)
|
|
|
|
const (
|
|
httpsScheme = "https"
|
|
httpScheme = "http"
|
|
tlsPort = "443"
|
|
)
|
|
|
|
// FasthttpProxyHTTPDialer returns a fasthttp.DialFunc that dials using
|
|
// the the env(HTTP_PROXY, HTTPS_PROXY and NO_PROXY) configured HTTP proxy.
|
|
//
|
|
// Example usage:
|
|
//
|
|
// c := &fasthttp.Client{
|
|
// Dial: FasthttpProxyHTTPDialer(),
|
|
// }
|
|
func FasthttpProxyHTTPDialer() fasthttp.DialFunc {
|
|
return FasthttpProxyHTTPDialerTimeout(0)
|
|
}
|
|
|
|
// FasthttpProxyHTTPDialer returns a fasthttp.DialFunc that dials using
|
|
// the env(HTTP_PROXY, HTTPS_PROXY and NO_PROXY) configured HTTP proxy using the given timeout.
|
|
//
|
|
// Example usage:
|
|
//
|
|
// c := &fasthttp.Client{
|
|
// Dial: FasthttpProxyHTTPDialerTimeout(time.Second * 2),
|
|
// }
|
|
func FasthttpProxyHTTPDialerTimeout(timeout time.Duration) fasthttp.DialFunc {
|
|
proxier := httpproxy.FromEnvironment().ProxyFunc()
|
|
|
|
// encoded auth barrier for http and https proxy.
|
|
authHTTPStorage := &atomic.Value{}
|
|
authHTTPSStorage := &atomic.Value{}
|
|
|
|
return func(addr string) (net.Conn, error) {
|
|
|
|
port, _, err := net.SplitHostPort(addr)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("unexpected addr format: %w", err)
|
|
}
|
|
|
|
reqURL := &url.URL{Host: addr, Scheme: httpScheme}
|
|
if port == tlsPort {
|
|
reqURL.Scheme = httpsScheme
|
|
}
|
|
proxyURL, err := proxier(reqURL)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if proxyURL == nil {
|
|
if timeout == 0 {
|
|
return fasthttp.Dial(addr)
|
|
}
|
|
return fasthttp.DialTimeout(addr, timeout)
|
|
}
|
|
|
|
var conn net.Conn
|
|
if timeout == 0 {
|
|
conn, err = fasthttp.Dial(proxyURL.Host)
|
|
} else {
|
|
conn, err = fasthttp.DialTimeout(proxyURL.Host, timeout)
|
|
}
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
req := "CONNECT " + addr + " HTTP/1.1\r\n"
|
|
|
|
if proxyURL.User != nil {
|
|
authBarrierStorage := authHTTPStorage
|
|
if port == tlsPort {
|
|
authBarrierStorage = authHTTPSStorage
|
|
}
|
|
|
|
auth := authBarrierStorage.Load()
|
|
if auth == nil {
|
|
authBarrier := base64.StdEncoding.EncodeToString([]byte(proxyURL.User.String()))
|
|
auth := &authBarrier
|
|
authBarrierStorage.Store(auth)
|
|
}
|
|
|
|
req += "Proxy-Authorization: Basic " + *auth.(*string) + "\r\n"
|
|
}
|
|
req += "\r\n"
|
|
|
|
if _, err := conn.Write([]byte(req)); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
res := fasthttp.AcquireResponse()
|
|
defer fasthttp.ReleaseResponse(res)
|
|
|
|
res.SkipBody = true
|
|
|
|
if err := res.Read(bufio.NewReader(conn)); err != nil {
|
|
if connErr := conn.Close(); connErr != nil {
|
|
return nil, fmt.Errorf("conn close err %v precede by read conn err %w", connErr, err)
|
|
}
|
|
return nil, err
|
|
}
|
|
if res.Header.StatusCode() != 200 {
|
|
if connErr := conn.Close(); connErr != nil {
|
|
return nil, fmt.Errorf(
|
|
"conn close err %w precede by connect to proxy: code: %d body %q",
|
|
connErr, res.StatusCode(), string(res.Body()))
|
|
}
|
|
return nil, fmt.Errorf("could not connect to proxy: code: %d body %q", res.StatusCode(), string(res.Body()))
|
|
}
|
|
return conn, nil
|
|
}
|
|
}
|