mirror of
https://github.com/gospider007/requests.git
synced 2025-12-24 13:57:52 +08:00
sync
This commit is contained in:
3
body.go
3
body.go
@@ -210,9 +210,6 @@ func (obj *RequestOption) newBody(val any) (io.Reader, *OrderData, bool, error)
|
||||
switch value := val.(type) {
|
||||
case *OrderData:
|
||||
return nil, value, true, nil
|
||||
case io.ReadCloser:
|
||||
obj.once = true
|
||||
return value, nil, true, nil
|
||||
case io.Reader:
|
||||
obj.once = true
|
||||
return value, nil, true, nil
|
||||
|
||||
59
client.go
59
client.go
@@ -3,9 +3,6 @@ package requests
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
utls "github.com/refraction-networking/utls"
|
||||
)
|
||||
@@ -72,62 +69,6 @@ func (obj *Client) Close() {
|
||||
obj.CloseConns()
|
||||
obj.cnl()
|
||||
}
|
||||
func (obj *Client) do(ctx *Response) (err error) {
|
||||
var redirectNum int
|
||||
for {
|
||||
redirectNum++
|
||||
err = obj.send(ctx)
|
||||
if ctx.Request().Body != nil {
|
||||
ctx.Request().Body.Close()
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if ctx.Option().MaxRedirect < 0 { //dis redirect
|
||||
return
|
||||
}
|
||||
if ctx.Option().MaxRedirect > 0 && redirectNum > ctx.Option().MaxRedirect {
|
||||
return
|
||||
}
|
||||
loc := ctx.response.Header.Get("Location")
|
||||
if loc == "" {
|
||||
return nil
|
||||
}
|
||||
u, err := ctx.Request().URL.Parse(loc)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse Location header %q: %v", loc, err)
|
||||
}
|
||||
ctx.request, err = NewRequestWithContext(ctx.Context(), http.MethodGet, u, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var shouldRedirect bool
|
||||
ctx.request.Method, shouldRedirect, _ = redirectBehavior(ctx.Request().Method, ctx.response, ctx.request)
|
||||
if !shouldRedirect {
|
||||
return nil
|
||||
}
|
||||
ctx.request.Response = ctx.response
|
||||
ctx.request.Header = make(http.Header)
|
||||
ctx.request.Header.Set("Referer", ctx.Request().URL.String())
|
||||
for key := range ctx.request.Header {
|
||||
if val := ctx.Request().Header.Get(key); val != "" {
|
||||
ctx.request.Header.Set(key, val)
|
||||
}
|
||||
}
|
||||
if getDomain(u) == getDomain(ctx.Request().URL) {
|
||||
if Authorization := ctx.Request().Header.Get("Authorization"); Authorization != "" {
|
||||
ctx.request.Header.Set("Authorization", Authorization)
|
||||
}
|
||||
cookies := Cookies(ctx.Request().Cookies()).String()
|
||||
if cookies != "" {
|
||||
ctx.request.Header.Set("Cookie", cookies)
|
||||
}
|
||||
addCookie(ctx.request, ctx.response.Cookies())
|
||||
}
|
||||
io.Copy(io.Discard, ctx.response.Body)
|
||||
ctx.response.Body.Close()
|
||||
}
|
||||
}
|
||||
func (obj *Client) send(ctx *Response) (err error) {
|
||||
if ctx.Option().Jar != nil {
|
||||
addCookie(ctx.Request(), ctx.Option().Jar.GetCookies(ctx.Request().URL))
|
||||
|
||||
@@ -93,6 +93,7 @@ type RequestOption struct {
|
||||
once bool
|
||||
orderHeaders *OrderData //order headers
|
||||
gospiderSpec *GospiderSpec
|
||||
disBody bool
|
||||
}
|
||||
|
||||
// Upload files with form-data,
|
||||
@@ -242,3 +243,10 @@ func (obj *Client) newRequestOption(option RequestOption) (RequestOption, error)
|
||||
}
|
||||
return option, err
|
||||
}
|
||||
func (obj *Client) newResponse(ctx context.Context, option RequestOption, uhref *url.URL, requestId string) *Response {
|
||||
option.Url = cloneUrl(uhref)
|
||||
response := NewResponse(ctx, option)
|
||||
response.client = obj
|
||||
response.requestId = requestId
|
||||
return response
|
||||
}
|
||||
|
||||
79
requests.go
79
requests.go
@@ -116,6 +116,54 @@ func (obj *Client) Trace(ctx context.Context, href string, options ...RequestOpt
|
||||
return obj.Request(ctx, http.MethodTrace, href, options...)
|
||||
}
|
||||
|
||||
// Define a function named Request that takes in four parameters:
|
||||
func (obj *Client) retryRequest(ctx context.Context, option RequestOption, uhref *url.URL, requestId string) (response *Response, err error) {
|
||||
defer func() {
|
||||
if errors.Is(err, errFatal) || response.Option().once {
|
||||
response.Option().MaxRetries = -1
|
||||
}
|
||||
}()
|
||||
var redirectNum int
|
||||
var loc *url.URL
|
||||
response = obj.newResponse(ctx, option, uhref, requestId)
|
||||
for {
|
||||
redirectNum++
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
err = ctx.Err()
|
||||
return
|
||||
default:
|
||||
}
|
||||
err = obj.request(response)
|
||||
if err != nil || response.Option().MaxRedirect < 0 || (response.Option().MaxRedirect > 0 && redirectNum > response.Option().MaxRedirect) {
|
||||
return
|
||||
}
|
||||
loc, err = response.Location()
|
||||
if err != nil || loc == nil {
|
||||
return
|
||||
}
|
||||
response.Close()
|
||||
switch response.StatusCode() {
|
||||
case 307, 308:
|
||||
if response.Option().once {
|
||||
return
|
||||
}
|
||||
response = obj.newResponse(ctx, option, loc, requestId)
|
||||
default:
|
||||
option.Method = http.MethodGet
|
||||
option.disBody = true
|
||||
option.Headers = nil
|
||||
option.Referer = response.Url().String()
|
||||
if getDomain(loc) == getDomain(response.Url()) {
|
||||
if Authorization := response.Request().Header.Get("Authorization"); Authorization != "" {
|
||||
option.Headers = map[string]any{"Authorization": Authorization}
|
||||
}
|
||||
}
|
||||
response = obj.newResponse(ctx, option, loc, requestId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Define a function named Request that takes in four parameters:
|
||||
func (obj *Client) Request(ctx context.Context, method string, href string, options ...RequestOption) (response *Response, err error) {
|
||||
if obj.closed {
|
||||
@@ -144,19 +192,9 @@ func (obj *Client) Request(ctx context.Context, method string, href string, opti
|
||||
}
|
||||
}
|
||||
for ; optionBak.MaxRetries >= 0; optionBak.MaxRetries-- {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
default:
|
||||
}
|
||||
option := optionBak
|
||||
option.Url = cloneUrl(uhref)
|
||||
response = NewResponse(ctx, option)
|
||||
response.client = obj
|
||||
response.requestId = requestId
|
||||
err = obj.request(response)
|
||||
if err == nil || errors.Is(err, errFatal) || response.Option().once {
|
||||
return
|
||||
response, err = obj.retryRequest(ctx, optionBak, uhref, requestId)
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
optionBak.MaxRetries = response.Option().MaxRetries
|
||||
}
|
||||
@@ -182,6 +220,9 @@ func (obj *Client) request(ctx *Response) (err error) {
|
||||
}
|
||||
}
|
||||
}
|
||||
if ctx.Request().Body != nil {
|
||||
ctx.Request().Body.Close()
|
||||
}
|
||||
}()
|
||||
if ctx.option.OptionCallBack != nil {
|
||||
if err = ctx.option.OptionCallBack(ctx); err != nil {
|
||||
@@ -232,9 +273,13 @@ func (obj *Client) request(ctx *Response) (err error) {
|
||||
}
|
||||
|
||||
//init body
|
||||
body, err := ctx.option.initBody(ctx.ctx)
|
||||
if err != nil {
|
||||
return tools.WrapError(err, errors.New("tempRequest init body error"), err)
|
||||
var body io.Reader
|
||||
if ctx.option.disBody {
|
||||
body = nil
|
||||
} else {
|
||||
if body, err = ctx.option.initBody(ctx.ctx); err != nil {
|
||||
return tools.WrapError(err, errors.New("tempRequest init body error"), err)
|
||||
}
|
||||
}
|
||||
//create request
|
||||
reqs, err := NewRequestWithContext(ctx.Context(), ctx.option.Method, href, body)
|
||||
@@ -279,7 +324,7 @@ func (obj *Client) request(ctx *Response) (err error) {
|
||||
//init spec
|
||||
|
||||
//send req
|
||||
err = obj.do(ctx)
|
||||
err = obj.send(ctx)
|
||||
if err != nil && err != ErrUseLastResponse {
|
||||
err = tools.WrapError(err, "client do error")
|
||||
return
|
||||
|
||||
39
tools.go
39
tools.go
@@ -129,45 +129,6 @@ func removeZone(host string) string {
|
||||
return host[:j] + host[i:]
|
||||
}
|
||||
|
||||
func outgoingLength(r *http.Request) int64 {
|
||||
if r.Body == nil || r.Body == http.NoBody {
|
||||
return 0
|
||||
}
|
||||
if r.ContentLength != 0 {
|
||||
return r.ContentLength
|
||||
}
|
||||
return -1
|
||||
}
|
||||
func redirectBehavior(reqMethod string, resp *http.Response, ireq *http.Request) (redirectMethod string, shouldRedirect, includeBody bool) {
|
||||
switch resp.StatusCode {
|
||||
case 301, 302, 303:
|
||||
redirectMethod = reqMethod
|
||||
shouldRedirect = true
|
||||
includeBody = false
|
||||
|
||||
// RFC 2616 allowed automatic redirection only with GET and
|
||||
// HEAD requests. RFC 7231 lifts this restriction, but we still
|
||||
// restrict other methods to GET to maintain compatibility.
|
||||
// See Issue 18570.
|
||||
if reqMethod != "GET" && reqMethod != "HEAD" {
|
||||
redirectMethod = "GET"
|
||||
}
|
||||
case 307, 308:
|
||||
redirectMethod = reqMethod
|
||||
shouldRedirect = true
|
||||
includeBody = true
|
||||
|
||||
if ireq.GetBody == nil && outgoingLength(ireq) != 0 {
|
||||
// We had a request body, and 307/308 require
|
||||
// re-sending it, but GetBody is not defined. So just
|
||||
// return this response to the user instead of an
|
||||
// error, like we did in Go 1.7 and earlier.
|
||||
shouldRedirect = false
|
||||
}
|
||||
}
|
||||
return redirectMethod, shouldRedirect, includeBody
|
||||
}
|
||||
|
||||
type requestBody struct {
|
||||
r io.Reader
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user