mirror of
https://github.com/Alexander-D-Karpov/about.git
synced 2026-03-16 22:06:08 +03:00
138 lines
3.2 KiB
Go
138 lines
3.2 KiB
Go
package plugins
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net"
|
|
"net/http"
|
|
"net/url"
|
|
"os"
|
|
"time"
|
|
)
|
|
|
|
func NewHTTPClient() *http.Client {
|
|
transport := &http.Transport{
|
|
DialContext: (&net.Dialer{
|
|
Timeout: 10 * time.Second,
|
|
KeepAlive: 30 * time.Second,
|
|
}).DialContext,
|
|
MaxIdleConns: 100,
|
|
MaxIdleConnsPerHost: 10,
|
|
IdleConnTimeout: 90 * time.Second,
|
|
TLSHandshakeTimeout: 10 * time.Second,
|
|
ExpectContinueTimeout: 1 * time.Second,
|
|
ResponseHeaderTimeout: 15 * time.Second,
|
|
}
|
|
|
|
if proxyURL := os.Getenv("HTTP_PROXY"); proxyURL != "" {
|
|
if parsed, err := url.Parse(proxyURL); err == nil {
|
|
transport.Proxy = http.ProxyURL(parsed)
|
|
}
|
|
} else if proxyURL := os.Getenv("HTTPS_PROXY"); proxyURL != "" {
|
|
if parsed, err := url.Parse(proxyURL); err == nil {
|
|
transport.Proxy = http.ProxyURL(parsed)
|
|
}
|
|
}
|
|
|
|
return &http.Client{
|
|
Transport: transport,
|
|
Timeout: 30 * time.Second,
|
|
}
|
|
}
|
|
|
|
func NewHTTPClientWithTimeout(timeout time.Duration) *http.Client {
|
|
transport := &http.Transport{
|
|
DialContext: (&net.Dialer{
|
|
Timeout: 5 * time.Second,
|
|
KeepAlive: 30 * time.Second,
|
|
}).DialContext,
|
|
MaxIdleConns: 50,
|
|
MaxIdleConnsPerHost: 5,
|
|
IdleConnTimeout: 60 * time.Second,
|
|
TLSHandshakeTimeout: 5 * time.Second,
|
|
ExpectContinueTimeout: 1 * time.Second,
|
|
ResponseHeaderTimeout: 10 * time.Second,
|
|
DisableKeepAlives: false,
|
|
ForceAttemptHTTP2: true,
|
|
}
|
|
|
|
if proxyURL := os.Getenv("HTTP_PROXY"); proxyURL != "" {
|
|
if parsed, err := url.Parse(proxyURL); err == nil {
|
|
transport.Proxy = http.ProxyURL(parsed)
|
|
}
|
|
} else if proxyURL := os.Getenv("HTTPS_PROXY"); proxyURL != "" {
|
|
if parsed, err := url.Parse(proxyURL); err == nil {
|
|
transport.Proxy = http.ProxyURL(parsed)
|
|
}
|
|
}
|
|
|
|
return &http.Client{
|
|
Transport: transport,
|
|
Timeout: timeout,
|
|
CheckRedirect: func(req *http.Request, via []*http.Request) error {
|
|
if len(via) >= 3 {
|
|
return fmt.Errorf("too many redirects")
|
|
}
|
|
return nil
|
|
},
|
|
}
|
|
}
|
|
|
|
func DoRequestWithContext(ctx context.Context, client *http.Client, req *http.Request) (*http.Response, error) {
|
|
if ctx == nil {
|
|
var cancel context.CancelFunc
|
|
ctx, cancel = context.WithTimeout(context.Background(), 15*time.Second)
|
|
defer cancel()
|
|
}
|
|
|
|
reqCtx, cancel := context.WithTimeout(ctx, 15*time.Second)
|
|
defer cancel()
|
|
|
|
req = req.WithContext(reqCtx)
|
|
req.Header.Set("User-Agent", "AboutPage/1.0 (about.akarpov.ru)")
|
|
req.Header.Set("Accept", "application/json")
|
|
req.Header.Set("Connection", "close")
|
|
|
|
done := make(chan struct {
|
|
resp *http.Response
|
|
err error
|
|
}, 1)
|
|
|
|
go func() {
|
|
defer func() {
|
|
if r := recover(); r != nil {
|
|
done <- struct {
|
|
resp *http.Response
|
|
err error
|
|
}{nil, fmt.Errorf("http request panic: %v", r)}
|
|
}
|
|
}()
|
|
|
|
resp, err := client.Do(req)
|
|
done <- struct {
|
|
resp *http.Response
|
|
err error
|
|
}{resp, err}
|
|
}()
|
|
|
|
select {
|
|
case result := <-done:
|
|
return result.resp, result.err
|
|
case <-reqCtx.Done():
|
|
return nil, reqCtx.Err()
|
|
}
|
|
}
|
|
|
|
func SafeHTTPRequest(ctx context.Context, client *http.Client, url string) (*http.Response, error) {
|
|
if client == nil {
|
|
client = NewHTTPClientWithTimeout(10 * time.Second)
|
|
}
|
|
|
|
req, err := http.NewRequest("GET", url, nil)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return DoRequestWithContext(ctx, client, req)
|
|
}
|