github.com/qiniu/go-sdk/v7@v7.27.0/internal/clientv2/request_compatible.go (about)

     1  package clientv2
     2  
     3  import (
     4  	"mime/multipart"
     5  	"net/http"
     6  	"net/textproto"
     7  	"net/url"
     8  )
     9  
    10  // 此处是为了版本兼容,sdk 支持最低版本为 go1.10, go1.13 提供 req.Clone 方法,
    11  // 此处 copy 高版本的 go 标准库方法
    12  func cloneReq(r *http.Request) *http.Request {
    13  	r2 := r.WithContext(r.Context())
    14  	if r.Header != nil {
    15  		r2.Header = cloneHeader(r.Header)
    16  	}
    17  	if r.Trailer != nil {
    18  		r2.Trailer = cloneHeader(r.Trailer)
    19  	}
    20  	if s := r.TransferEncoding; s != nil {
    21  		s2 := make([]string, len(s))
    22  		copy(s2, s)
    23  		r2.TransferEncoding = s2
    24  	}
    25  	r2.Form = cloneURLValues(r.Form)
    26  	r2.PostForm = cloneURLValues(r.PostForm)
    27  	r2.MultipartForm = cloneMultipartForm(r.MultipartForm)
    28  	return r2
    29  }
    30  
    31  func cloneHeader(h http.Header) http.Header {
    32  	if h == nil {
    33  		return nil
    34  	}
    35  
    36  	// Find total number of values.
    37  	nv := 0
    38  	for _, vv := range h {
    39  		nv += len(vv)
    40  	}
    41  	sv := make([]string, nv) // shared backing array for headers' values
    42  	h2 := make(http.Header, len(h))
    43  	for k, vv := range h {
    44  		n := copy(sv, vv)
    45  		h2[k] = sv[:n:n]
    46  		sv = sv[n:]
    47  	}
    48  	return h2
    49  }
    50  
    51  func cloneURLValues(v url.Values) url.Values {
    52  	if v == nil {
    53  		return nil
    54  	}
    55  
    56  	// http.Header and url.Values have the same representation, so temporarily
    57  	// treat it like http.Header, which does have a clone:
    58  	return url.Values(cloneHeader(http.Header(v)))
    59  }
    60  
    61  func cloneMultipartForm(f *multipart.Form) *multipart.Form {
    62  	if f == nil {
    63  		return nil
    64  	}
    65  	f2 := &multipart.Form{
    66  		Value: (map[string][]string)(cloneHeader(http.Header(f.Value))),
    67  	}
    68  	if f.File != nil {
    69  		m := make(map[string][]*multipart.FileHeader)
    70  		for k, vv := range f.File {
    71  			vv2 := make([]*multipart.FileHeader, len(vv))
    72  			for i, v := range vv {
    73  				vv2[i] = cloneMultipartFileHeader(v)
    74  			}
    75  			m[k] = vv2
    76  		}
    77  		f2.File = m
    78  	}
    79  	return f2
    80  }
    81  
    82  func cloneMultipartFileHeader(fh *multipart.FileHeader) *multipart.FileHeader {
    83  	if fh == nil {
    84  		return nil
    85  	}
    86  	fh2 := new(multipart.FileHeader)
    87  	*fh2 = *fh
    88  	fh2.Header = textproto.MIMEHeader(cloneHeader(http.Header(fh.Header)))
    89  	return fh2
    90  }