func (rp *ReverseProxy) UseOwnCACertificates(CaCertPool *x509.CertPool) {
	if transport, ok := rp.Transport.(*http.Transport); ok {
		if transport.TLSClientConfig == nil {
			transport.TLSClientConfig = &tls.Config{}
		}
		transport.TLSClientConfig.RootCAs = CaCertPool
	} else if transport, ok := rp.Transport.(*http3.RoundTripper); ok {
		if transport.TLSClientConfig == nil {
			transport.TLSClientConfig = &tls.Config{}
		}
		transport.TLSClientConfig.RootCAs = CaCertPool
	}
}
UseOwnCertificate is used to facilitate HTTPS proxying
with locally provided certificate.
package proxy
import (
	"context"
	"crypto/tls"
	"crypto/x509"
	"fmt"
	"io"
	"log"
	"net"
	"net/http"
	"net/url"
	"strings"
	"sync"
	"time"
	"golang.org/x/net/http2"
	"github.com/lucas-clemente/quic-go"
	"github.com/lucas-clemente/quic-go/http3"
	"github.com/tmpim/casket/caskethttp/httpserver"
)
var (
	defaultDialer = &net.Dialer{
		Timeout:   30 * time.Second,
		KeepAlive: 30 * time.Second,
		DualStack: true,
	}
	bufferPool = sync.Pool{New: createBuffer}
	defaultCryptoHandshakeTimeout = 10 * time.Second
)
func createBuffer() interface{} {
	return make([]byte, 0, 32*1024)
}
func pooledIoCopy(dst io.Writer, src io.Reader) {
	buf := bufferPool.Get().([]byte)
	defer bufferPool.Put(buf)
	bufCap := cap(buf)
	if _, err := io.CopyBuffer(dst, src, buf[0:bufCap:bufCap]); err != nil {
		log.Println("[ERROR] failed to copy buffer: ", err)
	}
}
var onExitFlushLoop func()
type ReverseProxy struct {
	Director func(*http.Request)
	Transport http.RoundTripper
	FlushInterval time.Duration
	dialer *net.Dialer
	srvResolver srvResolver
}
func socketDial(hostName string, timeout time.Duration) func(network, addr string) (conn net.Conn, err error) {
	return func(network, addr string) (conn net.Conn, err error) {
		return net.DialTimeout("unix", hostName[len("unix://"):], timeout)
	}
}
func (rp *ReverseProxy) srvDialerFunc(locator string, timeout time.Duration) func(network, addr string) (conn net.Conn, err error) {
	service := locator
	if strings.HasPrefix(locator, "srv://") {
		service = locator[6:]
	} else if strings.HasPrefix(locator, "srv+https://") {
		service = locator[12:]
	}
	return func(network, addr string) (conn net.Conn, err error) {
		_, addrs, err := rp.srvResolver.LookupSRV(context.Background(), "", "", service)
		if err != nil {
			return nil, err
		}
		return net.DialTimeout("tcp", fmt.Sprintf("%s:%d", addrs[0].Target, addrs[0].Port), timeout)
	}
}
func singleJoiningSlash(a, b string) string {
	aSlash := strings.HasSuffix(a, "/")
	bSlash := strings.HasPrefix(b, "/")
	switch {
	case aSlash && bSlash:
		return a + b[1:]
	case !aSlash && !bSlash && b != "":
		return a + "/" + b
	}
	return a + b
}
func NewSingleHostReverseProxy(target *url.URL, without string, keepalive int, timeout, fallbackDelay time.Duration) *ReverseProxy {
	targetQuery := target.RawQuery
	director := func(req *http.Request) {
		if target.Scheme == "unix" {
			req.URL.Scheme = "http"
			req.URL.Host = "socket"
		} else if target.Scheme == "srv" {
			req.URL.Scheme = "http"
			req.URL.Host = target.Host
		} else if target.Scheme == "srv+https" {
			req.URL.Scheme = "https"
			req.URL.Host = target.Host
		} else {
			req.URL.Scheme = target.Scheme
			req.URL.Host = target.Host
		}
		if without != "" {
			req.URL.Path = strings.TrimPrefix(req.URL.Path, without)
			if req.URL.Opaque != "" {
				req.URL.Opaque = strings.TrimPrefix(req.URL.Opaque, without)
			}
			if req.URL.RawPath != "" {
				req.URL.RawPath = strings.TrimPrefix(req.URL.RawPath, without)
			}
		}
		prefer := func(val, def string) string {
			if val != "" {
				return val
			}
			return def
		}
		if req.URL.Opaque != "" || target.Opaque != "" {
			req.URL.Opaque = singleJoiningSlash(
				prefer(target.Opaque, target.Path),
				prefer(req.URL.Opaque, req.URL.Path))
		}
		if req.URL.RawPath != "" || target.RawPath != "" {
			req.URL.RawPath = singleJoiningSlash(
				prefer(target.RawPath, target.Path),
				prefer(req.URL.RawPath, req.URL.Path))
		}
		req.URL.Path = singleJoiningSlash(target.Path, req.URL.Path)
		if target.Scheme == "unix" {
			socketPrefix := target.String()[len("unix://"):]
			req.URL.Path = strings.TrimPrefix(req.URL.Path, socketPrefix)
			if req.URL.Opaque != "" {
				req.URL.Opaque = strings.TrimPrefix(req.URL.Opaque, socketPrefix)
			}
			if req.URL.RawPath != "" {
				req.URL.RawPath = strings.TrimPrefix(req.URL.RawPath, socketPrefix)
			}
		}
		if targetQuery == "" || req.URL.RawQuery == "" {
			req.URL.RawQuery = targetQuery + req.URL.RawQuery
		} else {
			req.URL.RawQuery = targetQuery + "&" + req.URL.RawQuery
		}
	}
	dialer := *defaultDialer
	if timeout != defaultDialer.Timeout {
		dialer.Timeout = timeout
	}
	if fallbackDelay != defaultDialer.FallbackDelay {
		dialer.FallbackDelay = fallbackDelay
	}
	rp := &ReverseProxy{
		Director:      director,
		FlushInterval: 250 * time.Millisecond,  
		srvResolver:   net.DefaultResolver,
		dialer:        &dialer,
	}
	if target.Scheme == "unix" {
		rp.Transport = &http.Transport{
			Dial: socketDial(target.String(), timeout),
		}
	} else if target.Scheme == "quic" {
		rp.Transport = &http3.RoundTripper{
			QuicConfig: &quic.Config{
				HandshakeIdleTimeout: defaultCryptoHandshakeTimeout,
				KeepAlive:            true,
			},
		}
	} else if keepalive != http.DefaultMaxIdleConnsPerHost || strings.HasPrefix(target.Scheme, "srv") {
		dialFunc := rp.dialer.Dial
		if strings.HasPrefix(target.Scheme, "srv") {
			dialFunc = rp.srvDialerFunc(target.String(), timeout)
		}
		transport := &http.Transport{
			Proxy:                 http.ProxyFromEnvironment,
			Dial:                  dialFunc,
			TLSHandshakeTimeout:   defaultCryptoHandshakeTimeout,
			ExpectContinueTimeout: 1 * time.Second,
		}
		if keepalive == 0 {
			transport.DisableKeepAlives = true
		} else {
			transport.MaxIdleConnsPerHost = keepalive
		}
		if httpserver.HTTP2 {
			if err := http2.ConfigureTransport(transport); err != nil {
				log.Println("[ERROR] failed to configure transport to use HTTP/2: ", err)
			}
		}
		rp.Transport = transport
	} else {
		transport := &http.Transport{
			Proxy: http.ProxyFromEnvironment,
			Dial:  rp.dialer.Dial,
		}
		if httpserver.HTTP2 {
			if err := http2.ConfigureTransport(transport); err != nil {
				log.Println("[ERROR] failed to configure transport to use HTTP/2: ", err)
			}
		}
		rp.Transport = transport
	}
	return rp
}
func (rp *ReverseProxy) UseInsecureTransport() {
	if transport, ok := rp.Transport.(*http.Transport); ok {
		if transport.TLSClientConfig == nil {
			transport.TLSClientConfig = &tls.Config{}
		}
		transport.TLSClientConfig.InsecureSkipVerify = true
	} else if transport, ok := rp.Transport.(*http3.RoundTripper); ok {
		if transport.TLSClientConfig == nil {
			transport.TLSClientConfig = &tls.Config{}
		}
		transport.TLSClientConfig.InsecureSkipVerify = true
	}
}