func ReleaseAgent(a *Agent) {
	a.reset()
	agentPool.Put(a)
}
ReleaseAgent returns a acquired via AcquireAgent to Agent pool.

It is forbidden accessing req and/or its' members after returning
it to Agent pool.
package fiber
import (
	"bytes"
	"crypto/tls"
	"encoding/xml"
	"fmt"
	"io"
	"io/ioutil"
	"mime/multipart"
	"net"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"sync"
	"time"
	"github.com/gofiber/fiber/v2/internal/go-json"
	"github.com/gofiber/fiber/v2/utils"
	"github.com/valyala/fasthttp"
)
type Request = fasthttp.Request
type Response = fasthttp.Response
type Args = fasthttp.Args
var defaultClient Client
type Client struct {
	UserAgent string
	NoDefaultUserAgentHeader bool
	JSONEncoder utils.JSONMarshal
	JSONDecoder utils.JSONUnmarshal
}
func Get(url string) *Agent { return defaultClient.Get(url) }
func (c *Client) Get(url string) *Agent {
	return c.createAgent(MethodGet, url)
}
func Head(url string) *Agent { return defaultClient.Head(url) }
func (c *Client) Head(url string) *Agent {
	return c.createAgent(MethodHead, url)
}
func Post(url string) *Agent { return defaultClient.Post(url) }
func (c *Client) Post(url string) *Agent {
	return c.createAgent(MethodPost, url)
}
func Put(url string) *Agent { return defaultClient.Put(url) }
func (c *Client) Put(url string) *Agent {
	return c.createAgent(MethodPut, url)
}
func Patch(url string) *Agent { return defaultClient.Patch(url) }
func (c *Client) Patch(url string) *Agent {
	return c.createAgent(MethodPatch, url)
}
func Delete(url string) *Agent { return defaultClient.Delete(url) }
func (c *Client) Delete(url string) *Agent {
	return c.createAgent(MethodDelete, url)
}
func (c *Client) createAgent(method, url string) *Agent {
	a := AcquireAgent()
	a.req.Header.SetMethod(method)
	a.req.SetRequestURI(url)
	a.Name = c.UserAgent
	a.NoDefaultUserAgentHeader = c.NoDefaultUserAgentHeader
	a.jsonDecoder = c.JSONDecoder
	a.jsonEncoder = c.JSONEncoder
	if err := a.Parse(); err != nil {
		a.errs = append(a.errs, err)
	}
	return a
}
type Agent struct {
	Name string
	NoDefaultUserAgentHeader bool
	*fasthttp.HostClient
	req               *Request
	resp              *Response
	dest              []byte
	args              *Args
	timeout           time.Duration
	errs              []error
	formFiles         []*FormFile
	debugWriter       io.Writer
	mw                multipartWriter
	jsonEncoder       utils.JSONMarshal
	jsonDecoder       utils.JSONUnmarshal
	maxRedirectsCount int
	boundary          string
	reuse             bool
	parsed            bool
}
func (a *Agent) Parse() error {
	if a.parsed {
		return nil
	}
	a.parsed = true
	uri := a.req.URI()
	isTLS := false
	scheme := uri.Scheme()
	if bytes.Equal(scheme, strHTTPS) {
		isTLS = true
	} else if !bytes.Equal(scheme, strHTTP) {
		return fmt.Errorf("unsupported protocol %q. http and https are supported", scheme)
	}
	name := a.Name
	if name == "" && !a.NoDefaultUserAgentHeader {
		name = defaultUserAgent
	}
	a.HostClient = &fasthttp.HostClient{
		Addr:                     addMissingPort(string(uri.Host()), isTLS),
		Name:                     name,
		NoDefaultUserAgentHeader: a.NoDefaultUserAgentHeader,
		IsTLS:                    isTLS,
	}
	return nil
}
func addMissingPort(addr string, isTLS bool) string {
	n := strings.Index(addr, ":")
	if n >= 0 {
		return addr
	}
	port := 80
	if isTLS {
		port = 443
	}
	return net.JoinHostPort(addr, strconv.Itoa(port))
}
func (a *Agent) Set(k, v string) *Agent {
	a.req.Header.Set(k, v)
	return a
}
func (a *Agent) SetBytesK(k []byte, v string) *Agent {
	a.req.Header.SetBytesK(k, v)
	return a
}
func (a *Agent) SetBytesV(k string, v []byte) *Agent {
	a.req.Header.SetBytesV(k, v)
	return a
}
func (a *Agent) SetBytesKV(k []byte, v []byte) *Agent {
	a.req.Header.SetBytesKV(k, v)
	return a
}
func (a *Agent) Add(k, v string) *Agent {
	a.req.Header.Add(k, v)
	return a
}
func (a *Agent) AddBytesK(k []byte, v string) *Agent {
	a.req.Header.AddBytesK(k, v)
	return a
}
func (a *Agent) AddBytesV(k string, v []byte) *Agent {
	a.req.Header.AddBytesV(k, v)
	return a
}
func (a *Agent) AddBytesKV(k []byte, v []byte) *Agent {
	a.req.Header.AddBytesKV(k, v)
	return a
}
func (a *Agent) ConnectionClose() *Agent {
	a.req.Header.SetConnectionClose()
	return a
}
func (a *Agent) UserAgent(userAgent string) *Agent {
	a.req.Header.SetUserAgent(userAgent)
	return a
}
func (a *Agent) UserAgentBytes(userAgent []byte) *Agent {
	a.req.Header.SetUserAgentBytes(userAgent)
	return a
}
func (a *Agent) Cookie(key, value string) *Agent {
	a.req.Header.SetCookie(key, value)
	return a
}
func (a *Agent) CookieBytesK(key []byte, value string) *Agent {
	a.req.Header.SetCookieBytesK(key, value)
	return a
}
func (a *Agent) CookieBytesKV(key, value []byte) *Agent {
	a.req.Header.SetCookieBytesKV(key, value)
	return a
}
func (a *Agent) Cookies(kv ...string) *Agent {
	for i := 1; i < len(kv); i += 2 {
		a.req.Header.SetCookie(kv[i-1], kv[i])
	}
	return a
}
func (a *Agent) CookiesBytesKV(kv ...[]byte) *Agent {
	for i := 1; i < len(kv); i += 2 {
		a.req.Header.SetCookieBytesKV(kv[i-1], kv[i])
	}
	return a
}
func (a *Agent) Referer(referer string) *Agent {
	a.req.Header.SetReferer(referer)
	return a
}
func (a *Agent) RefererBytes(referer []byte) *Agent {
	a.req.Header.SetRefererBytes(referer)
	return a
}
func (a *Agent) ContentType(contentType string) *Agent {
	a.req.Header.SetContentType(contentType)
	return a
}
func (a *Agent) ContentTypeBytes(contentType []byte) *Agent {
	a.req.Header.SetContentTypeBytes(contentType)
	return a
}
func (a *Agent) Host(host string) *Agent {
	a.req.URI().SetHost(host)
	return a
}
func (a *Agent) HostBytes(host []byte) *Agent {
	a.req.URI().SetHostBytes(host)
	return a
}
func (a *Agent) QueryString(queryString string) *Agent {
	a.req.URI().SetQueryString(queryString)
	return a
}
func (a *Agent) QueryStringBytes(queryString []byte) *Agent {
	a.req.URI().SetQueryStringBytes(queryString)
	return a
}
func (a *Agent) BasicAuth(username, password string) *Agent {
	a.req.URI().SetUsername(username)
	a.req.URI().SetPassword(password)
	return a
}
func (a *Agent) BasicAuthBytes(username, password []byte) *Agent {
	a.req.URI().SetUsernameBytes(username)
	a.req.URI().SetPasswordBytes(password)
	return a
}
func (a *Agent) BodyString(bodyString string) *Agent {
	a.req.SetBodyString(bodyString)
	return a
}
func (a *Agent) Body(body []byte) *Agent {
	a.req.SetBody(body)
	return a
}
func (a *Agent) BodyStream(bodyStream io.Reader, bodySize int) *Agent {
	a.req.SetBodyStream(bodyStream, bodySize)
	return a
}
func (a *Agent) JSON(v interface{}) *Agent {
	if a.jsonEncoder == nil {
		a.jsonEncoder = json.Marshal
	}
	a.req.Header.SetContentType(MIMEApplicationJSON)
	if body, err := a.jsonEncoder(v); err != nil {
		a.errs = append(a.errs, err)
	} else {
		a.req.SetBody(body)
	}
	return a
}
func (a *Agent) XML(v interface{}) *Agent {
	a.req.Header.SetContentType(MIMEApplicationXML)
	if body, err := xml.Marshal(v); err != nil {
		a.errs = append(a.errs, err)
	} else {
		a.req.SetBody(body)
	}
	return a
}
func (a *Agent) Form(args *Args) *Agent {
	a.req.Header.SetContentType(MIMEApplicationForm)
	if args != nil {
		a.req.SetBody(args.QueryString())
	}
	return a
}
type FormFile struct {
	Fieldname string
	Name string
	Content []byte
	autoRelease bool
}
func (a *Agent) FileData(formFiles ...*FormFile) *Agent {
	a.formFiles = append(a.formFiles, formFiles...)
	return a
}
func (a *Agent) SendFile(filename string, fieldname ...string) *Agent {
	content, err := ioutil.ReadFile(filepath.Clean(filename))
	if err != nil {
		a.errs = append(a.errs, err)
		return a
	}
	ff := AcquireFormFile()
	if len(fieldname) > 0 && fieldname[0] != "" {
		ff.Fieldname = fieldname[0]
	} else {
		ff.Fieldname = "file" + strconv.Itoa(len(a.formFiles)+1)
	}
	ff.Name = filepath.Base(filename)
	ff.Content = append(ff.Content, content...)
	ff.autoRelease = true
	a.formFiles = append(a.formFiles, ff)
	return a
}
func (a *Agent) SendFiles(filenamesAndFieldnames ...string) *Agent {
	pairs := len(filenamesAndFieldnames)
	if pairs&1 == 1 {
		filenamesAndFieldnames = append(filenamesAndFieldnames, "")
	}
	for i := 0; i < pairs; i += 2 {
		a.SendFile(filenamesAndFieldnames[i], filenamesAndFieldnames[i+1])
	}
	return a
}
func (a *Agent) Boundary(boundary string) *Agent {
	a.boundary = boundary
	return a
}
func (a *Agent) MultipartForm(args *Args) *Agent {
	if a.mw == nil {
		a.mw = multipart.NewWriter(a.req.BodyWriter())
	}
	if a.boundary != "" {
		if err := a.mw.SetBoundary(a.boundary); err != nil {
			a.errs = append(a.errs, err)
			return a
		}
	}
	a.req.Header.SetMultipartFormBoundary(a.mw.Boundary())
	if args != nil {
		args.VisitAll(func(key, value []byte) {
			if err := a.mw.WriteField(utils.UnsafeString(key), utils.UnsafeString(value)); err != nil {
				a.errs = append(a.errs, err)
			}
		})
	}
	for _, ff := range a.formFiles {
		w, err := a.mw.CreateFormFile(ff.Fieldname, ff.Name)
		if err != nil {
			a.errs = append(a.errs, err)
			continue
		}
		if _, err = w.Write(ff.Content); err != nil {
			a.errs = append(a.errs, err)
		}
	}
	if err := a.mw.Close(); err != nil {
		a.errs = append(a.errs, err)
	}
	return a
}
func (a *Agent) Debug(w ...io.Writer) *Agent {
	a.debugWriter = os.Stdout
	if len(w) > 0 {
		a.debugWriter = w[0]
	}
	return a
}
func (a *Agent) Timeout(timeout time.Duration) *Agent {
	a.timeout = timeout
	return a
}
func (a *Agent) Reuse() *Agent {
	a.reuse = true
	return a
}
func (a *Agent) InsecureSkipVerify() *Agent {
	if a.HostClient.TLSConfig == nil {
		a.HostClient.TLSConfig = &tls.Config{InsecureSkipVerify: true}
	} else {
		a.HostClient.TLSConfig.InsecureSkipVerify = true
	}
	return a
}
func (a *Agent) TLSConfig(config *tls.Config) *Agent {
	a.HostClient.TLSConfig = config
	return a
}
func (a *Agent) MaxRedirectsCount(count int) *Agent {
	a.maxRedirectsCount = count
	return a
}
func (a *Agent) JSONEncoder(jsonEncoder utils.JSONMarshal) *Agent {
	a.jsonEncoder = jsonEncoder
	return a
}
func (a *Agent) JSONDecoder(jsonDecoder utils.JSONUnmarshal) *Agent {
	a.jsonDecoder = jsonDecoder
	return a
}
func (a *Agent) Request() *Request {
	return a.req
}
func (a *Agent) SetResponse(customResp *Response) *Agent {
	a.resp = customResp
	return a
}
func (a *Agent) Dest(dest []byte) *Agent {
	a.dest = dest
	return a
}
var warnOnce sync.Once
func (a *Agent) Bytes() (code int, body []byte, errs []error) {
	warnOnce.Do(func() {
		fmt.Println("[Warning] client is still in beta, API might change in the future!")
	})
	defer a.release()
	if errs = append(errs, a.errs...); len(errs) > 0 {
		return
	}
	var (
		req     = a.req
		resp    *Response
		nilResp bool
	)
	if a.resp == nil {
		resp = AcquireResponse()
		nilResp = true
	} else {
		resp = a.resp
	}
	defer func() {
		if a.debugWriter != nil {
			printDebugInfo(req, resp, a.debugWriter)
		}
		if len(errs) == 0 {
			code = resp.StatusCode()
		}
		body = append(a.dest, resp.Body()...)
		if nilResp {
			ReleaseResponse(resp)
		}
	}()
	if a.timeout > 0 {
		if err := a.HostClient.DoTimeout(req, resp, a.timeout); err != nil {
			errs = append(errs, err)
			return
		}
	} else if a.maxRedirectsCount > 0 && (string(req.Header.Method()) == MethodGet || string(req.Header.Method()) == MethodHead) {
		if err := a.HostClient.DoRedirects(req, resp, a.maxRedirectsCount); err != nil {
			errs = append(errs, err)
			return
		}
	} else if err := a.HostClient.Do(req, resp); err != nil {
		errs = append(errs, err)
	}
	return
}
func printDebugInfo(req *Request, resp *Response, w io.Writer) {
	msg := fmt.Sprintf("Connected to %s(%s)\r\n\r\n", req.URI().Host(), resp.RemoteAddr())
	_, _ = w.Write(utils.UnsafeBytes(msg))
	_, _ = req.WriteTo(w)
	_, _ = resp.WriteTo(w)
}
func (a *Agent) String() (int, string, []error) {
	code, body, errs := a.Bytes()
	return code, utils.UnsafeString(body), errs
}
func (a *Agent) Struct(v interface{}) (code int, body []byte, errs []error) {
	if a.jsonDecoder == nil {
		a.jsonDecoder = json.Unmarshal
	}
	if code, body, errs = a.Bytes(); len(errs) > 0 {
		return
	}
	if err := a.jsonDecoder(body, v); err != nil {
		errs = append(errs, err)
	}
	return
}
func (a *Agent) release() {
	if !a.reuse {
		ReleaseAgent(a)
	} else {
		a.errs = a.errs[:0]
	}
}
func (a *Agent) reset() {
	a.HostClient = nil
	a.req.Reset()
	a.resp = nil
	a.dest = nil
	a.timeout = 0
	a.args = nil
	a.errs = a.errs[:0]
	a.debugWriter = nil
	a.mw = nil
	a.reuse = false
	a.parsed = false
	a.maxRedirectsCount = 0
	a.boundary = ""
	a.Name = ""
	a.NoDefaultUserAgentHeader = false
	for i, ff := range a.formFiles {
		if ff.autoRelease {
			ReleaseFormFile(ff)
		}
		a.formFiles[i] = nil
	}
	a.formFiles = a.formFiles[:0]
}
var (
	clientPool   sync.Pool
	agentPool    sync.Pool
	responsePool sync.Pool
	argsPool     sync.Pool
	formFilePool sync.Pool
)
func AcquireClient() *Client {
	v := clientPool.Get()
	if v == nil {
		return &Client{}
	}
	return v.(*Client)
}
func ReleaseClient(c *Client) {
	c.UserAgent = ""
	c.NoDefaultUserAgentHeader = false
	clientPool.Put(c)
}
func AcquireAgent() *Agent {
	v := agentPool.Get()
	if v == nil {
		return &Agent{req: &Request{}}
	}
	return v.(*Agent)
}