mirror of
https://github.com/gospider007/requests.git
synced 2025-12-24 13:57:52 +08:00
sync
This commit is contained in:
322
client.go
322
client.go
@@ -1,161 +1,161 @@
|
||||
package requests
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/url"
|
||||
|
||||
"net/http"
|
||||
|
||||
"github.com/gospider007/gtls"
|
||||
)
|
||||
|
||||
// Connection Management
|
||||
type Client struct {
|
||||
option ClientOption
|
||||
transport *roundTripper
|
||||
ctx context.Context
|
||||
cnl context.CancelFunc
|
||||
closed bool
|
||||
}
|
||||
|
||||
var defaultClient, _ = NewClient(context.TODO())
|
||||
|
||||
// New Connection Management
|
||||
func NewClient(preCtx context.Context, options ...ClientOption) (*Client, error) {
|
||||
if preCtx == nil {
|
||||
preCtx = context.TODO()
|
||||
}
|
||||
var option ClientOption
|
||||
if len(options) > 0 {
|
||||
option = options[0]
|
||||
}
|
||||
result := new(Client)
|
||||
result.ctx, result.cnl = context.WithCancel(preCtx)
|
||||
result.transport = newRoundTripper(result.ctx, option)
|
||||
result.option = option
|
||||
//cookiesjar
|
||||
if !result.option.DisCookie {
|
||||
if result.option.Jar == nil {
|
||||
result.option.Jar = NewJar()
|
||||
}
|
||||
}
|
||||
var err error
|
||||
if result.option.Proxy != "" {
|
||||
_, err = gtls.VerifyProxy(result.option.Proxy)
|
||||
}
|
||||
return result, err
|
||||
}
|
||||
|
||||
// Modifying the client's proxy
|
||||
func (obj *Client) SetProxy(proxyUrl string) (err error) {
|
||||
_, err = gtls.VerifyProxy(proxyUrl)
|
||||
if err == nil {
|
||||
obj.option.Proxy = proxyUrl
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Modify the proxy method of the client
|
||||
func (obj *Client) SetGetProxy(getProxy func(ctx context.Context, url *url.URL) (string, error)) {
|
||||
obj.transport.setGetProxy(getProxy)
|
||||
}
|
||||
|
||||
// Close idle connections. If the connection is in use, wait until it ends before closing
|
||||
func (obj *Client) CloseConns() {
|
||||
obj.transport.closeConns()
|
||||
}
|
||||
|
||||
// Close the connection, even if it is in use, it will be closed
|
||||
func (obj *Client) ForceCloseConns() {
|
||||
obj.transport.forceCloseConns()
|
||||
}
|
||||
|
||||
// Close the client and cannot be used again after shutdown
|
||||
func (obj *Client) Close() {
|
||||
obj.closed = true
|
||||
obj.ForceCloseConns()
|
||||
obj.cnl()
|
||||
}
|
||||
|
||||
// func checkRedirect(req *http.Request, via []*http.Request) error {
|
||||
// ctxData := GetReqCtxData(req.Context())
|
||||
// if ctxData.maxRedirect == 0 || ctxData.maxRedirect >= len(via) {
|
||||
// return nil
|
||||
// }
|
||||
// return http.ErrUseLastResponse
|
||||
// }
|
||||
|
||||
func (obj *Client) do(req *http.Request, option *RequestOption) (resp *http.Response, err error) {
|
||||
var redirectNum int
|
||||
for {
|
||||
redirectNum++
|
||||
resp, err = obj.send(req, option)
|
||||
if req.Body != nil {
|
||||
req.Body.Close()
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if option.MaxRedirect < 0 { //dis redirect
|
||||
return
|
||||
}
|
||||
if option.MaxRedirect > 0 && redirectNum > option.MaxRedirect {
|
||||
return
|
||||
}
|
||||
loc := resp.Header.Get("Location")
|
||||
if loc == "" {
|
||||
return resp, nil
|
||||
}
|
||||
u, err := req.URL.Parse(loc)
|
||||
if err != nil {
|
||||
return resp, fmt.Errorf("failed to parse Location header %q: %v", loc, err)
|
||||
}
|
||||
ireq, err := NewRequestWithContext(req.Context(), http.MethodGet, u, nil)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
var shouldRedirect bool
|
||||
ireq.Method, shouldRedirect, _ = redirectBehavior(req.Method, resp, ireq)
|
||||
if !shouldRedirect {
|
||||
return resp, nil
|
||||
}
|
||||
ireq.Response = resp
|
||||
ireq.Header = defaultHeaders()
|
||||
ireq.Header.Set("Referer", req.URL.String())
|
||||
for key := range ireq.Header {
|
||||
if val := req.Header.Get(key); val != "" {
|
||||
ireq.Header.Set(key, val)
|
||||
}
|
||||
}
|
||||
if getDomain(u) == getDomain(req.URL) {
|
||||
if Authorization := req.Header.Get("Authorization"); Authorization != "" {
|
||||
ireq.Header.Set("Authorization", Authorization)
|
||||
}
|
||||
cookies := Cookies(req.Cookies()).String()
|
||||
if cookies != "" {
|
||||
ireq.Header.Set("Cookie", cookies)
|
||||
}
|
||||
addCookie(ireq, resp.Cookies())
|
||||
}
|
||||
io.Copy(io.Discard, resp.Body)
|
||||
resp.Body.Close()
|
||||
req = ireq
|
||||
}
|
||||
}
|
||||
func (obj *Client) send(req *http.Request, option *RequestOption) (resp *http.Response, err error) {
|
||||
if option.Jar != nil {
|
||||
addCookie(req, option.Jar.GetCookies(req.URL))
|
||||
}
|
||||
resp, err = obj.transport.RoundTrip(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if option.Jar != nil {
|
||||
if rc := resp.Cookies(); len(rc) > 0 {
|
||||
option.Jar.SetCookies(req.URL, rc)
|
||||
}
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
package requests
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/url"
|
||||
|
||||
"net/http"
|
||||
|
||||
"github.com/gospider007/gtls"
|
||||
)
|
||||
|
||||
// Connection Management
|
||||
type Client struct {
|
||||
option ClientOption
|
||||
transport *roundTripper
|
||||
ctx context.Context
|
||||
cnl context.CancelFunc
|
||||
closed bool
|
||||
}
|
||||
|
||||
var defaultClient, _ = NewClient(context.TODO())
|
||||
|
||||
// New Connection Management
|
||||
func NewClient(preCtx context.Context, options ...ClientOption) (*Client, error) {
|
||||
if preCtx == nil {
|
||||
preCtx = context.TODO()
|
||||
}
|
||||
var option ClientOption
|
||||
if len(options) > 0 {
|
||||
option = options[0]
|
||||
}
|
||||
result := new(Client)
|
||||
result.ctx, result.cnl = context.WithCancel(preCtx)
|
||||
result.transport = newRoundTripper(result.ctx, option)
|
||||
result.option = option
|
||||
//cookiesjar
|
||||
if !result.option.DisCookie {
|
||||
if result.option.Jar == nil {
|
||||
result.option.Jar = NewJar()
|
||||
}
|
||||
}
|
||||
var err error
|
||||
if result.option.Proxy != "" {
|
||||
_, err = gtls.VerifyProxy(result.option.Proxy)
|
||||
}
|
||||
return result, err
|
||||
}
|
||||
|
||||
// Modifying the client's proxy
|
||||
func (obj *Client) SetProxy(proxyUrl string) (err error) {
|
||||
_, err = gtls.VerifyProxy(proxyUrl)
|
||||
if err == nil {
|
||||
obj.option.Proxy = proxyUrl
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Modify the proxy method of the client
|
||||
func (obj *Client) SetGetProxy(getProxy func(ctx context.Context, url *url.URL) (string, error)) {
|
||||
obj.transport.setGetProxy(getProxy)
|
||||
}
|
||||
|
||||
// Close idle connections. If the connection is in use, wait until it ends before closing
|
||||
func (obj *Client) CloseConns() {
|
||||
obj.transport.closeConns()
|
||||
}
|
||||
|
||||
// Close the connection, even if it is in use, it will be closed
|
||||
func (obj *Client) ForceCloseConns() {
|
||||
obj.transport.forceCloseConns()
|
||||
}
|
||||
|
||||
// Close the client and cannot be used again after shutdown
|
||||
func (obj *Client) Close() {
|
||||
obj.closed = true
|
||||
obj.ForceCloseConns()
|
||||
obj.cnl()
|
||||
}
|
||||
|
||||
// func checkRedirect(req *http.Request, via []*http.Request) error {
|
||||
// ctxData := GetReqCtxData(req.Context())
|
||||
// if ctxData.maxRedirect == 0 || ctxData.maxRedirect >= len(via) {
|
||||
// return nil
|
||||
// }
|
||||
// return http.ErrUseLastResponse
|
||||
// }
|
||||
|
||||
func (obj *Client) do(req *http.Request, option *RequestOption) (resp *http.Response, err error) {
|
||||
var redirectNum int
|
||||
for {
|
||||
redirectNum++
|
||||
resp, err = obj.send(req, option)
|
||||
if req.Body != nil {
|
||||
req.Body.Close()
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if option.MaxRedirect < 0 { //dis redirect
|
||||
return
|
||||
}
|
||||
if option.MaxRedirect > 0 && redirectNum > option.MaxRedirect {
|
||||
return
|
||||
}
|
||||
loc := resp.Header.Get("Location")
|
||||
if loc == "" {
|
||||
return resp, nil
|
||||
}
|
||||
u, err := req.URL.Parse(loc)
|
||||
if err != nil {
|
||||
return resp, fmt.Errorf("failed to parse Location header %q: %v", loc, err)
|
||||
}
|
||||
ireq, err := NewRequestWithContext(req.Context(), http.MethodGet, u, nil)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
var shouldRedirect bool
|
||||
ireq.Method, shouldRedirect, _ = redirectBehavior(req.Method, resp, ireq)
|
||||
if !shouldRedirect {
|
||||
return resp, nil
|
||||
}
|
||||
ireq.Response = resp
|
||||
ireq.Header = defaultHeaders()
|
||||
ireq.Header.Set("Referer", req.URL.String())
|
||||
for key := range ireq.Header {
|
||||
if val := req.Header.Get(key); val != "" {
|
||||
ireq.Header.Set(key, val)
|
||||
}
|
||||
}
|
||||
if getDomain(u) == getDomain(req.URL) {
|
||||
if Authorization := req.Header.Get("Authorization"); Authorization != "" {
|
||||
ireq.Header.Set("Authorization", Authorization)
|
||||
}
|
||||
cookies := Cookies(req.Cookies()).String()
|
||||
if cookies != "" {
|
||||
ireq.Header.Set("Cookie", cookies)
|
||||
}
|
||||
addCookie(ireq, resp.Cookies())
|
||||
}
|
||||
io.Copy(io.Discard, resp.Body)
|
||||
resp.Body.Close()
|
||||
req = ireq
|
||||
}
|
||||
}
|
||||
func (obj *Client) send(req *http.Request, option *RequestOption) (resp *http.Response, err error) {
|
||||
if option.Jar != nil {
|
||||
addCookie(req, option.Jar.GetCookies(req.URL))
|
||||
}
|
||||
resp, err = obj.transport.RoundTrip(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if option.Jar != nil {
|
||||
if rc := resp.Cookies(); len(rc) > 0 {
|
||||
option.Jar.SetCookies(req.URL, rc)
|
||||
}
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user