|
|
package clientv2
|
|
|
|
|
|
import (
|
|
|
"context"
|
|
|
"mime/multipart"
|
|
|
"net/http"
|
|
|
"net/textproto"
|
|
|
"net/url"
|
|
|
)
|
|
|
|
|
|
// 此处是为了版本兼容,sdk 支持最低版本为 go1.10, go1.13 提供 req.Clone 方法,
|
|
|
// 此处 copy 高版本的 go 标准库方法
|
|
|
func cloneReq(ctx context.Context, r *http.Request) *http.Request {
|
|
|
if ctx == nil {
|
|
|
panic("nil context")
|
|
|
}
|
|
|
|
|
|
r2 := r.WithContext(ctx)
|
|
|
if r.Header != nil {
|
|
|
r2.Header = cloneHeader(r.Header)
|
|
|
}
|
|
|
if r.Trailer != nil {
|
|
|
r2.Trailer = cloneHeader(r.Trailer)
|
|
|
}
|
|
|
if s := r.TransferEncoding; s != nil {
|
|
|
s2 := make([]string, len(s))
|
|
|
copy(s2, s)
|
|
|
r2.TransferEncoding = s2
|
|
|
}
|
|
|
r2.Form = cloneURLValues(r.Form)
|
|
|
r2.PostForm = cloneURLValues(r.PostForm)
|
|
|
r2.MultipartForm = cloneMultipartForm(r.MultipartForm)
|
|
|
return r2
|
|
|
}
|
|
|
|
|
|
func cloneHeader(h http.Header) http.Header {
|
|
|
if h == nil {
|
|
|
return nil
|
|
|
}
|
|
|
|
|
|
// Find total number of values.
|
|
|
nv := 0
|
|
|
for _, vv := range h {
|
|
|
nv += len(vv)
|
|
|
}
|
|
|
sv := make([]string, nv) // shared backing array for headers' values
|
|
|
h2 := make(http.Header, len(h))
|
|
|
for k, vv := range h {
|
|
|
n := copy(sv, vv)
|
|
|
h2[k] = sv[:n:n]
|
|
|
sv = sv[n:]
|
|
|
}
|
|
|
return h2
|
|
|
}
|
|
|
|
|
|
func cloneURLValues(v url.Values) url.Values {
|
|
|
if v == nil {
|
|
|
return nil
|
|
|
}
|
|
|
|
|
|
// http.Header and url.Values have the same representation, so temporarily
|
|
|
// treat it like http.Header, which does have a clone:
|
|
|
return url.Values(cloneHeader(http.Header(v)))
|
|
|
}
|
|
|
|
|
|
func cloneMultipartForm(f *multipart.Form) *multipart.Form {
|
|
|
if f == nil {
|
|
|
return nil
|
|
|
}
|
|
|
f2 := &multipart.Form{
|
|
|
Value: (map[string][]string)(cloneHeader(http.Header(f.Value))),
|
|
|
}
|
|
|
if f.File != nil {
|
|
|
m := make(map[string][]*multipart.FileHeader)
|
|
|
for k, vv := range f.File {
|
|
|
vv2 := make([]*multipart.FileHeader, len(vv))
|
|
|
for i, v := range vv {
|
|
|
vv2[i] = cloneMultipartFileHeader(v)
|
|
|
}
|
|
|
m[k] = vv2
|
|
|
}
|
|
|
f2.File = m
|
|
|
}
|
|
|
return f2
|
|
|
}
|
|
|
|
|
|
func cloneMultipartFileHeader(fh *multipart.FileHeader) *multipart.FileHeader {
|
|
|
if fh == nil {
|
|
|
return nil
|
|
|
}
|
|
|
fh2 := new(multipart.FileHeader)
|
|
|
*fh2 = *fh
|
|
|
fh2.Header = textproto.MIMEHeader(cloneHeader(http.Header(fh.Header)))
|
|
|
return fh2
|
|
|
}
|