github.com/codingeasygo/util@v0.0.0-20231206062002-1ce2f004b7d9/xhttp/xhttp.go (about)

     1  package xhttp
     2  
     3  import (
     4  	"bytes"
     5  	"crypto/tls"
     6  	"encoding/json"
     7  	"encoding/xml"
     8  	"fmt"
     9  	"io"
    10  	"io/ioutil"
    11  	"mime/multipart"
    12  	"net/http"
    13  	"net/http/cookiejar"
    14  	"net/url"
    15  	"os"
    16  	"path"
    17  	"path/filepath"
    18  	"strings"
    19  	"testing"
    20  
    21  	"github.com/codingeasygo/util/xmap"
    22  )
    23  
    24  const (
    25  	//ContentTypeForm is web form content type
    26  	ContentTypeForm = "application/x-www-form-urlencoded"
    27  	//ContentTypeJSON is json content type
    28  	ContentTypeJSON = "application/json;charset=utf-8"
    29  	//ContentTypeXML is xml content type
    30  	ContentTypeXML = "application/xml;charset=utf-8"
    31  )
    32  
    33  var insecureSkipVerify = false
    34  var enableCookie = false
    35  
    36  func init() {
    37  	initClient()
    38  }
    39  
    40  func initClient() {
    41  	DefaultTransport = &http.Transport{
    42  		TLSClientConfig: &tls.Config{InsecureSkipVerify: insecureSkipVerify},
    43  	}
    44  	DefaultClient = &http.Client{
    45  		Transport: DefaultTransport,
    46  	}
    47  	if enableCookie {
    48  		DefaultClient.Jar, _ = cookiejar.New(nil)
    49  	}
    50  }
    51  
    52  //DefaultTransport is default http transport
    53  var DefaultTransport *http.Transport
    54  
    55  //DefaultClient is default http client
    56  var DefaultClient *http.Client
    57  
    58  //Shared is share client
    59  var Shared *Client = &Client{Raw: defaultRaw}
    60  
    61  //DisableInsecureVerify will disable verify insecure
    62  func DisableInsecureVerify() {
    63  	insecureSkipVerify = true
    64  	initClient()
    65  }
    66  
    67  //EnableInsecureVerify will enable verify insecure
    68  func EnableInsecureVerify() {
    69  	insecureSkipVerify = false
    70  	initClient()
    71  }
    72  
    73  //EnableCookie will enable cookie
    74  func EnableCookie() {
    75  	enableCookie = true
    76  	initClient()
    77  }
    78  
    79  //DisableCookie will disable cookie
    80  func DisableCookie() {
    81  	enableCookie = false
    82  	initClient()
    83  }
    84  
    85  //ClearCookie will clear cookie
    86  func ClearCookie() {
    87  	if enableCookie {
    88  		DefaultClient.Jar, _ = cookiejar.New(nil)
    89  	} else {
    90  		DefaultClient.Jar = nil
    91  	}
    92  }
    93  
    94  func defaultRaw(method, uri string, header xmap.M, body io.Reader) (req *http.Request, res *http.Response, err error) {
    95  	c := &RawClient{C: DefaultClient}
    96  	req, res, err = c.RawRequest(method, uri, header, body)
    97  	return
    98  }
    99  
   100  //RawClient is http raw request impl
   101  type RawClient struct {
   102  	C *http.Client
   103  }
   104  
   105  //RawRequest will do raw request
   106  func (r *RawClient) RawRequest(method, uri string, header xmap.M, body io.Reader) (req *http.Request, res *http.Response, err error) {
   107  	req, err = http.NewRequest(method, uri, body)
   108  	if err != nil {
   109  		return
   110  	}
   111  	for k, v := range header {
   112  		req.Header.Set(k, fmt.Sprintf("%v", v))
   113  	}
   114  	res, err = r.C.Do(req)
   115  	return
   116  }
   117  
   118  //GetBytes will get bytes from remote
   119  func GetBytes(format string, args ...interface{}) (data []byte, err error) {
   120  	return Shared.GetBytes(format, args...)
   121  }
   122  
   123  //GetHeaderBytes will get bytes from remote
   124  func GetHeaderBytes(header xmap.M, format string, args ...interface{}) (data []byte, res *http.Response, err error) {
   125  	return Shared.GetHeaderBytes(header, format, args...)
   126  }
   127  
   128  //GetText will get text from remote
   129  func GetText(format string, args ...interface{}) (data string, err error) {
   130  	return Shared.GetText(format, args...)
   131  }
   132  
   133  //GetHeaderText will get text from remote
   134  func GetHeaderText(header xmap.M, format string, args ...interface{}) (data string, res *http.Response, err error) {
   135  	return Shared.GetHeaderText(header, format, args...)
   136  }
   137  
   138  //GetMap will get map from remote
   139  func GetMap(format string, args ...interface{}) (data xmap.M, err error) {
   140  	return Shared.GetMap(format, args...)
   141  }
   142  
   143  //GetHeaderMap will get map from remote
   144  func GetHeaderMap(header xmap.M, format string, args ...interface{}) (data xmap.M, res *http.Response, err error) {
   145  	return Shared.GetHeaderMap(header, format, args...)
   146  }
   147  
   148  //GetJSON will get json from remote
   149  func GetJSON(result interface{}, format string, args ...interface{}) (err error) {
   150  	return Shared.GetJSON(result, format, args...)
   151  }
   152  
   153  //GetHeaderMap will get map from remote
   154  func GetHeaderJSON(result interface{}, header xmap.M, format string, args ...interface{}) (res *http.Response, err error) {
   155  	return Shared.GetHeaderJSON(result, header, format, args...)
   156  }
   157  
   158  //PostBytes will get bytes from remote
   159  func PostBytes(body io.Reader, format string, args ...interface{}) (data []byte, err error) {
   160  	return Shared.PostBytes(body, format, args...)
   161  }
   162  
   163  //PostTypeBytes will get bytes from remote
   164  func PostTypeBytes(contentType string, body io.Reader, format string, args ...interface{}) (data []byte, err error) {
   165  	return Shared.PostTypeBytes(contentType, body, format, args...)
   166  }
   167  
   168  //PostHeaderBytes will get bytes from remote
   169  func PostHeaderBytes(header xmap.M, body io.Reader, format string, args ...interface{}) (data []byte, res *http.Response, err error) {
   170  	return Shared.PostHeaderBytes(header, body, format, args...)
   171  }
   172  
   173  //PostText will get text from remote
   174  func PostText(body io.Reader, format string, args ...interface{}) (data string, err error) {
   175  	return Shared.PostText(body, format, args...)
   176  }
   177  
   178  //PostTypeText will get text from remote
   179  func PostTypeText(contentType string, body io.Reader, format string, args ...interface{}) (data string, err error) {
   180  	return Shared.PostTypeText(contentType, body, format, args...)
   181  }
   182  
   183  //PostHeaderText will get text from remote
   184  func PostHeaderText(header xmap.M, body io.Reader, format string, args ...interface{}) (data string, res *http.Response, err error) {
   185  	return Shared.PostHeaderText(header, body, format, args...)
   186  }
   187  
   188  //PostMap will get map from remote
   189  func PostMap(body io.Reader, format string, args ...interface{}) (data xmap.M, err error) {
   190  	return Shared.PostMap(body, format, args...)
   191  }
   192  
   193  //PostTypeMap will get map from remote
   194  func PostTypeMap(contentType string, body io.Reader, format string, args ...interface{}) (data xmap.M, err error) {
   195  	return Shared.PostTypeMap(contentType, body, format, args...)
   196  }
   197  
   198  //PostHeaderMap will get map from remote
   199  func PostHeaderMap(header xmap.M, body io.Reader, format string, args ...interface{}) (data xmap.M, res *http.Response, err error) {
   200  	return Shared.PostHeaderMap(header, body, format, args...)
   201  }
   202  
   203  //PostJSONMap will get map from remote
   204  func PostJSONMap(body interface{}, format string, args ...interface{}) (data xmap.M, err error) {
   205  	return Shared.PostJSONMap(body, format, args...)
   206  }
   207  
   208  //PostMap will get map from remote
   209  func PostJSON(result interface{}, body io.Reader, format string, args ...interface{}) (err error) {
   210  	return Shared.PostJSON(result, body, format, args...)
   211  }
   212  
   213  //PostTypeMap will get map from remote
   214  func PostTypeJSON(result interface{}, contentType string, body io.Reader, format string, args ...interface{}) (err error) {
   215  	return Shared.PostTypeJSON(result, contentType, body, format, args...)
   216  }
   217  
   218  //PostHeaderMap will get map from remote
   219  func PostHeaderJSON(result interface{}, header xmap.M, body io.Reader, format string, args ...interface{}) (res *http.Response, err error) {
   220  	return Shared.PostHeaderJSON(result, header, body, format, args...)
   221  }
   222  
   223  //PostJSONMap will get map from remote
   224  func PostJSONJSON(result interface{}, body interface{}, format string, args ...interface{}) (err error) {
   225  	return Shared.PostJSONJSON(result, body, format, args...)
   226  }
   227  
   228  //MethodBytes will do http request, read reponse and parse to bytes
   229  func MethodBytes(method string, header xmap.M, body io.Reader, format string, args ...interface{}) (data []byte, res *http.Response, err error) {
   230  	return Shared.MethodBytes(method, header, body, format, args...)
   231  }
   232  
   233  //MethodBytes will do http request, read reponse and parse to string
   234  func MethodText(method string, header xmap.M, body io.Reader, format string, args ...interface{}) (data string, res *http.Response, err error) {
   235  	return Shared.MethodText(method, header, body, format, args...)
   236  }
   237  
   238  //MethodBytes will do http request, read reponse and parse to map
   239  func MethodMap(method string, header xmap.M, body io.Reader, format string, args ...interface{}) (data xmap.M, res *http.Response, err error) {
   240  	return Shared.MethodMap(method, header, body, format, args...)
   241  }
   242  
   243  //PostXMLText will get text from remote
   244  func PostXMLText(v interface{}, format string, args ...interface{}) (data string, err error) {
   245  	return Shared.PostXMLText(v, format, args...)
   246  }
   247  
   248  //PostFormText will get text from remote
   249  func PostFormText(form xmap.M, format string, args ...interface{}) (data string, err error) {
   250  	return Shared.PostFormText(form, format, args...)
   251  }
   252  
   253  //PostFormMap will get map from remote
   254  func PostFormMap(form xmap.M, format string, args ...interface{}) (data xmap.M, err error) {
   255  	return Shared.PostFormMap(form, format, args...)
   256  }
   257  
   258  //PostMultipartBytes will get bytes from remote
   259  func PostMultipartBytes(header, fields xmap.M, format string, args ...interface{}) (data []byte, res *http.Response, err error) {
   260  	return Shared.PostMultipartBytes(header, fields, format, args...)
   261  }
   262  
   263  //PostMultipartText will get bytes from remote
   264  func PostMultipartText(header, fields xmap.M, format string, args ...interface{}) (data string, err error) {
   265  	return Shared.PostMultipartText(header, fields, format, args...)
   266  }
   267  
   268  //PostMultipartMap will get map from remote
   269  func PostMultipartMap(header, fields xmap.M, format string, args ...interface{}) (data xmap.M, err error) {
   270  	return Shared.PostMultipartMap(header, fields, format, args...)
   271  }
   272  
   273  //UploadText will get text from remote
   274  func UploadText(fields xmap.M, filekey, filename, format string, args ...interface{}) (text string, err error) {
   275  	return Shared.UploadText(fields, filekey, filename, format, args...)
   276  }
   277  
   278  //UploadHeaderText will get text from remote
   279  func UploadHeaderText(header xmap.M, fields xmap.M, filekey, filename, format string, args ...interface{}) (text string, res *http.Response, err error) {
   280  	return Shared.UploadHeaderText(header, fields, filekey, filename, format, args...)
   281  }
   282  
   283  //UploadMap will get map from remote
   284  func UploadMap(fields xmap.M, filekey, filename, format string, args ...interface{}) (data xmap.M, err error) {
   285  	return Shared.UploadMap(fields, filekey, filename, format, args...)
   286  }
   287  
   288  //Download will download file to save path
   289  func Download(saveto string, format string, args ...interface{}) (saved int64, err error) {
   290  	return Shared.Download(saveto, format, args...)
   291  }
   292  
   293  //DownloadHeader will download file to save path
   294  func DownloadHeader(saveto string, header xmap.M, format string, args ...interface{}) (saved int64, err error) {
   295  	return Shared.DownloadHeader(saveto, header, format, args...)
   296  }
   297  
   298  //RawRequestF is raw request func define
   299  type RawRequestF func(method, uri string, header xmap.M, body io.Reader) (req *http.Request, res *http.Response, err error)
   300  
   301  //Client is http get client
   302  type Client struct {
   303  	Raw RawRequestF
   304  }
   305  
   306  //NewRawClient will return new client
   307  func NewRawClient(raw RawRequestF) (client *Client) {
   308  	client = &Client{Raw: raw}
   309  	return
   310  }
   311  
   312  //NewClient will return new client by http.Client
   313  func NewClient(raw *http.Client) (client *Client) {
   314  	c := &RawClient{C: raw}
   315  	client = &Client{
   316  		Raw: c.RawRequest,
   317  	}
   318  	return
   319  }
   320  
   321  func mustOk(res *http.Response, err error) error {
   322  	if err == nil && res.StatusCode != 200 {
   323  		err = fmt.Errorf("status code is %v", res.StatusCode)
   324  	}
   325  	return err
   326  }
   327  
   328  //GetBytes will do http request and read the bytes response
   329  func (c *Client) GetBytes(format string, args ...interface{}) (data []byte, err error) {
   330  	data, res, err := c.GetHeaderBytes(nil, format, args...)
   331  	err = mustOk(res, err)
   332  	return
   333  }
   334  
   335  //GetHeaderBytes will do http request and read the text response
   336  func (c *Client) GetHeaderBytes(header xmap.M, format string, args ...interface{}) (data []byte, res *http.Response, err error) {
   337  	remote := fmt.Sprintf(format, args...)
   338  	_, res, err = c.Raw("GET", remote, header, nil)
   339  	if err != nil {
   340  		return
   341  	}
   342  	defer res.Body.Close()
   343  	data, err = ioutil.ReadAll(res.Body)
   344  	return
   345  }
   346  
   347  //GetText will do http request and read the text response
   348  func (c *Client) GetText(format string, args ...interface{}) (data string, err error) {
   349  	data, res, err := c.GetHeaderText(nil, format, args...)
   350  	err = mustOk(res, err)
   351  	return
   352  }
   353  
   354  //GetHeaderText will do http request and read the text response
   355  func (c *Client) GetHeaderText(header xmap.M, format string, args ...interface{}) (data string, res *http.Response, err error) {
   356  	bys, res, err := c.GetHeaderBytes(header, format, args...)
   357  	data = string(bys)
   358  	return
   359  }
   360  
   361  //GetMap will do http request, read reponse and parse to map
   362  func (c *Client) GetMap(format string, args ...interface{}) (data xmap.M, err error) {
   363  	data, res, err := c.GetHeaderMap(nil, format, args...)
   364  	err = mustOk(res, err)
   365  	return
   366  }
   367  
   368  //GetHeaderMap will do http request, read reponse and parse to map
   369  func (c *Client) GetHeaderMap(header xmap.M, format string, args ...interface{}) (data xmap.M, res *http.Response, err error) {
   370  	text, res, err := c.GetHeaderBytes(header, format, args...)
   371  	if err == nil {
   372  		data, err = xmap.MapVal(text)
   373  	}
   374  	return
   375  }
   376  
   377  //GetJSON will do http request, read reponse and parse to json
   378  func (c *Client) GetJSON(value interface{}, format string, args ...interface{}) (err error) {
   379  	err = mustOk(c.GetHeaderJSON(value, nil, format, args...))
   380  	return
   381  }
   382  
   383  //GetHeaderMap will do http request, read reponse and parse to map
   384  func (c *Client) GetHeaderJSON(value interface{}, header xmap.M, format string, args ...interface{}) (res *http.Response, err error) {
   385  	text, res, err := c.GetHeaderBytes(header, format, args...)
   386  	if err == nil {
   387  		err = json.Unmarshal(text, value)
   388  	}
   389  	return
   390  }
   391  
   392  //PostBytes will do http request and read the bytes response
   393  func (c *Client) PostBytes(body io.Reader, format string, args ...interface{}) (data []byte, err error) {
   394  	data, res, err := c.PostHeaderBytes(nil, body, format, args...)
   395  	err = mustOk(res, err)
   396  	return
   397  }
   398  
   399  //PostTypeBytes will do http request and read the bytes response
   400  func (c *Client) PostTypeBytes(contentType string, body io.Reader, format string, args ...interface{}) (data []byte, err error) {
   401  	data, res, err := c.PostHeaderBytes(xmap.M{"Content-Type": contentType}, body, format, args...)
   402  	err = mustOk(res, err)
   403  	return
   404  }
   405  
   406  //PostHeaderBytes will do http request and read the text response
   407  func (c *Client) PostHeaderBytes(header xmap.M, body io.Reader, format string, args ...interface{}) (data []byte, res *http.Response, err error) {
   408  	remote := fmt.Sprintf(format, args...)
   409  	_, res, err = c.Raw("POST", remote, header, body)
   410  	if err != nil {
   411  		return
   412  	}
   413  	defer res.Body.Close()
   414  	data, err = ioutil.ReadAll(res.Body)
   415  	return
   416  }
   417  
   418  //PostText will do http request and read the text response
   419  func (c *Client) PostText(body io.Reader, format string, args ...interface{}) (data string, err error) {
   420  	data, res, err := c.PostHeaderText(nil, body, format, args...)
   421  	err = mustOk(res, err)
   422  	return
   423  }
   424  
   425  //PostTypeText will do http request and read the text response
   426  func (c *Client) PostTypeText(contentType string, body io.Reader, format string, args ...interface{}) (data string, err error) {
   427  	data, res, err := c.PostHeaderText(xmap.M{"Content-Type": contentType}, body, format, args...)
   428  	err = mustOk(res, err)
   429  	return
   430  }
   431  
   432  //PostHeaderText will do http request and read the text response
   433  func (c *Client) PostHeaderText(header xmap.M, body io.Reader, format string, args ...interface{}) (data string, res *http.Response, err error) {
   434  	bys, res, err := c.PostHeaderBytes(header, body, format, args...)
   435  	data = string(bys)
   436  	return
   437  }
   438  
   439  //PostMap will do http request, read reponse and parse to map
   440  func (c *Client) PostMap(body io.Reader, format string, args ...interface{}) (data xmap.M, err error) {
   441  	data, res, err := c.PostHeaderMap(nil, body, format, args...)
   442  	err = mustOk(res, err)
   443  	return
   444  }
   445  
   446  //PostTypeMap will do http request, read reponse and parse to map
   447  func (c *Client) PostTypeMap(contentType string, body io.Reader, format string, args ...interface{}) (data xmap.M, err error) {
   448  	data, res, err := c.PostHeaderMap(xmap.M{"Content-Type": contentType}, body, format, args...)
   449  	err = mustOk(res, err)
   450  	return
   451  }
   452  
   453  //PostHeaderMap will do http request, read reponse and parse to map
   454  func (c *Client) PostHeaderMap(header xmap.M, body io.Reader, format string, args ...interface{}) (data xmap.M, res *http.Response, err error) {
   455  	text, res, err := c.PostHeaderBytes(header, body, format, args...)
   456  	if err == nil {
   457  		data, err = xmap.MapVal(text)
   458  	}
   459  	return
   460  }
   461  
   462  //PostJSONMap will do http request, read reponse and parse to map
   463  func (c *Client) PostJSONMap(body interface{}, format string, args ...interface{}) (data xmap.M, err error) {
   464  	bys, err := json.Marshal(body)
   465  	if err != nil {
   466  		return
   467  	}
   468  	data, res, err := c.PostHeaderMap(xmap.M{"Content-Type": ContentTypeJSON}, bytes.NewBuffer(bys), format, args...)
   469  	err = mustOk(res, err)
   470  	return
   471  }
   472  
   473  //PostMap will do http request, read reJSONponse and parse by json
   474  func (c *Client) PostJSON(result interface{}, body io.Reader, format string, args ...interface{}) (err error) {
   475  	data, res, err := c.PostHeaderBytes(nil, body, format, args...)
   476  	err = mustOk(res, err)
   477  	if err == nil {
   478  		err = json.Unmarshal(data, result)
   479  	}
   480  	return
   481  }
   482  
   483  //PostTypeJSON will do http request, read reponse and parse by json
   484  func (c *Client) PostTypeJSON(result interface{}, contentType string, body io.Reader, format string, args ...interface{}) (err error) {
   485  	data, res, err := c.PostHeaderBytes(xmap.M{"Content-Type": contentType}, body, format, args...)
   486  	err = mustOk(res, err)
   487  	if err == nil {
   488  		err = json.Unmarshal(data, result)
   489  	}
   490  	return
   491  }
   492  
   493  //PostHeaderJSON will do http request, read reponse and parse by json
   494  func (c *Client) PostHeaderJSON(result interface{}, header xmap.M, body io.Reader, format string, args ...interface{}) (res *http.Response, err error) {
   495  	data, res, err := c.PostHeaderBytes(header, body, format, args...)
   496  	if err == nil {
   497  		err = json.Unmarshal(data, result)
   498  	}
   499  	return
   500  }
   501  
   502  //PostJSONJSON will do http request, read reponse and parse by json
   503  func (c *Client) PostJSONJSON(result interface{}, body interface{}, format string, args ...interface{}) (err error) {
   504  	bys, err := json.Marshal(body)
   505  	if err != nil {
   506  		return
   507  	}
   508  	data, res, err := c.PostHeaderBytes(xmap.M{"Content-Type": ContentTypeJSON}, bytes.NewBuffer(bys), format, args...)
   509  	err = mustOk(res, err)
   510  	if err == nil {
   511  		err = json.Unmarshal(data, result)
   512  	}
   513  	return
   514  }
   515  
   516  //MethodBytes will do http request, read reponse and parse to bytes
   517  func (c *Client) MethodBytes(method string, header xmap.M, body io.Reader, format string, args ...interface{}) (data []byte, res *http.Response, err error) {
   518  	remote := fmt.Sprintf(format, args...)
   519  	_, res, err = c.Raw(method, remote, header, body)
   520  	if err != nil {
   521  		return
   522  	}
   523  	defer res.Body.Close()
   524  	data, err = ioutil.ReadAll(res.Body)
   525  	return
   526  }
   527  
   528  //MethodBytes will do http request, read reponse and parse to string
   529  func (c *Client) MethodText(method string, header xmap.M, body io.Reader, format string, args ...interface{}) (data string, res *http.Response, err error) {
   530  	bytes, res, err := c.MethodBytes(method, header, body, format, args...)
   531  	if len(bytes) > 0 {
   532  		data = string(bytes)
   533  	}
   534  	return
   535  }
   536  
   537  //MethodBytes will do http request, read reponse and parse to map
   538  func (c *Client) MethodMap(method string, header xmap.M, body io.Reader, format string, args ...interface{}) (data xmap.M, res *http.Response, err error) {
   539  	text, res, err := c.MethodBytes(method, header, body, format, args...)
   540  	if err == nil {
   541  		data, err = xmap.MapVal(text)
   542  	}
   543  	return
   544  }
   545  
   546  //PostXMLText will do http request, read reponse and parse to map
   547  func (c *Client) PostXMLText(v interface{}, format string, args ...interface{}) (data string, err error) {
   548  	bys, err := xml.Marshal(v)
   549  	if err != nil {
   550  		return
   551  	}
   552  	data, res, err := c.PostHeaderText(xmap.M{"Content-Type": ContentTypeXML}, bytes.NewBuffer(bys), format, args...)
   553  	err = mustOk(res, err)
   554  	return
   555  }
   556  
   557  //PostFormText will do http request, read reponse and parse to map
   558  func (c *Client) PostFormText(form xmap.M, format string, args ...interface{}) (data string, err error) {
   559  	query := url.Values{}
   560  	for k, v := range form {
   561  		query.Set(k, fmt.Sprintf("%v", v))
   562  	}
   563  	buf := bytes.NewBufferString(query.Encode())
   564  	data, res, err := c.PostHeaderText(xmap.M{"Content-Type": ContentTypeForm}, buf, format, args...)
   565  	err = mustOk(res, err)
   566  	return
   567  }
   568  
   569  //PostFormMap will do http request, read reponse and parse to map
   570  func (c *Client) PostFormMap(form xmap.M, format string, args ...interface{}) (data xmap.M, err error) {
   571  	query := url.Values{}
   572  	for k, v := range form {
   573  		query.Set(k, fmt.Sprintf("%v", v))
   574  	}
   575  	buf := bytes.NewBufferString(query.Encode())
   576  	data, res, err := c.PostHeaderMap(xmap.M{"Content-Type": ContentTypeForm}, buf, format, args...)
   577  	err = mustOk(res, err)
   578  	return
   579  }
   580  
   581  //CreateMultipartBody will create multipart body
   582  func CreateMultipartBody(fields xmap.M) (*bytes.Buffer, string) {
   583  	bodyBuf := &bytes.Buffer{}
   584  	bodyWriter := multipart.NewWriter(bodyBuf)
   585  	for k, v := range fields {
   586  		bodyWriter.WriteField(k, fmt.Sprintf("%v", v))
   587  	}
   588  	ctype := bodyWriter.FormDataContentType()
   589  	bodyWriter.Close()
   590  	return bodyBuf, ctype
   591  }
   592  
   593  //PostMultipartBytes will do http request, read reponse and parse to map
   594  func (c *Client) PostMultipartBytes(header, fields xmap.M, format string, args ...interface{}) (data []byte, res *http.Response, err error) {
   595  	bodyBuf, ctype := CreateMultipartBody(fields)
   596  	remote := fmt.Sprintf(format, args...)
   597  	if header == nil {
   598  		header = xmap.M{}
   599  	}
   600  	header.SetValue("Content-Type", ctype)
   601  	_, res, err = c.Raw("POST", remote, header, bodyBuf)
   602  	if err != nil {
   603  		return
   604  	}
   605  	defer res.Body.Close()
   606  	data, err = ioutil.ReadAll(res.Body)
   607  	return
   608  }
   609  
   610  //PostMultipartText will do http request, read reponse and parse to map
   611  func (c *Client) PostMultipartText(header, fields xmap.M, format string, args ...interface{}) (data string, err error) {
   612  	bytes, res, err := c.PostMultipartBytes(header, fields, format, args...)
   613  	err = mustOk(res, err)
   614  	if len(bytes) > 0 {
   615  		data = string(bytes)
   616  	}
   617  	return
   618  }
   619  
   620  //PostMultipartMap will do http request, read reponse and parse to map
   621  func (c *Client) PostMultipartMap(header, fields xmap.M, format string, args ...interface{}) (data xmap.M, err error) {
   622  	bytes, res, err := c.PostMultipartBytes(header, fields, format, args...)
   623  	err = mustOk(res, err)
   624  	if err == nil {
   625  		data, err = xmap.MapVal(bytes)
   626  	}
   627  	return
   628  }
   629  
   630  //FileBodyTask is upload task
   631  type FileBodyTask struct {
   632  	reader *io.PipeReader
   633  	writer *io.PipeWriter
   634  }
   635  
   636  //CreateFileBodyTask will create the file upload task
   637  func CreateFileBodyTask(fields xmap.M, filekey string, filename string) (*FileBodyTask, io.Reader, string) {
   638  	task := &FileBodyTask{}
   639  	reader, ctype := task.Start(fields, filekey, filename)
   640  	return task, reader, ctype
   641  }
   642  
   643  //Start will start the file upload body
   644  func (f *FileBodyTask) Start(fields xmap.M, filekey string, filename string) (io.Reader, string) {
   645  	f.reader, f.writer = io.Pipe()
   646  	bodyWriter := multipart.NewWriter(f.writer)
   647  	go func() {
   648  		err := f.run(bodyWriter, fields, filekey, filename)
   649  		bodyWriter.Close()
   650  		if err == nil {
   651  			f.writer.Close()
   652  		} else {
   653  			f.writer.CloseWithError(err)
   654  		}
   655  	}()
   656  	return f.reader, bodyWriter.FormDataContentType()
   657  }
   658  
   659  func (f *FileBodyTask) run(bodyWriter *multipart.Writer, fields xmap.M, filekey string, filename string) error {
   660  	for k, v := range fields {
   661  		bodyWriter.WriteField(k, fmt.Sprintf("%v", v))
   662  	}
   663  	fileWriter, err := bodyWriter.CreateFormFile(filekey, filename)
   664  	if err == nil {
   665  		var file *os.File
   666  		file, err = os.Open(filename)
   667  		if err == nil {
   668  			defer file.Close()
   669  			_, err = io.Copy(fileWriter, file)
   670  		}
   671  	}
   672  	return err
   673  }
   674  
   675  //Close the upload file body
   676  func (f *FileBodyTask) Close() error {
   677  	if f.reader != nil {
   678  		f.reader.Close()
   679  	}
   680  	if f.writer != nil {
   681  		f.writer.Close()
   682  	}
   683  	return nil
   684  }
   685  
   686  //UploadText upload file and get text response
   687  func (c *Client) UploadText(fields xmap.M, filekey, filename, format string, args ...interface{}) (text string, err error) {
   688  	text, res, err := c.UploadHeaderText(nil, fields, filekey, filename, format, args...)
   689  	err = mustOk(res, err)
   690  	return
   691  }
   692  
   693  //UploadHeaderText upload file and get text response
   694  func (c *Client) UploadHeaderText(header xmap.M, fields xmap.M, filekey, filename, format string, args ...interface{}) (text string, res *http.Response, err error) {
   695  	var ctype string
   696  	var bodyBuf io.Reader
   697  	var task *FileBodyTask
   698  	task, bodyBuf, ctype = CreateFileBodyTask(fields, filekey, filename)
   699  	defer task.Close()
   700  	remote := fmt.Sprintf(format, args...)
   701  	if header == nil {
   702  		header = xmap.M{}
   703  	}
   704  	header.SetValue("Content-Type", ctype)
   705  	_, res, err = c.Raw("POST", remote, header, bodyBuf)
   706  	if err != nil {
   707  		return
   708  	}
   709  	defer res.Body.Close()
   710  	bys, err := ioutil.ReadAll(res.Body)
   711  	text = string(bys)
   712  	return
   713  }
   714  
   715  //UploadMap will upload file and get map response
   716  func (c *Client) UploadMap(fields xmap.M, filekey, filename, format string, args ...interface{}) (data xmap.M, err error) {
   717  	text, res, err := c.UploadHeaderText(nil, fields, filekey, filename, format, args...)
   718  	err = mustOk(res, err)
   719  	if err == nil {
   720  		data, err = xmap.MapVal(text)
   721  	}
   722  	return
   723  }
   724  
   725  //Download will download the file to save path
   726  func (c *Client) Download(saveto string, format string, args ...interface{}) (saved int64, err error) {
   727  	saved, err = c.DownloadHeader(saveto, nil, format, args...)
   728  	return
   729  }
   730  
   731  //DownloadHeader will download the file to save path
   732  func (c *Client) DownloadHeader(saveto string, header xmap.M, format string, args ...interface{}) (saved int64, err error) {
   733  	req, res, err := c.Raw("GET", fmt.Sprintf(format, args...), header, nil)
   734  	if err != nil {
   735  		return
   736  	}
   737  	defer res.Body.Close()
   738  	if res.StatusCode != 200 {
   739  		err = fmt.Errorf("status code is %v", res.StatusCode)
   740  		return
   741  	}
   742  	savepath := saveto
   743  	if info, err := os.Stat(saveto); err == nil && info.IsDir() {
   744  		var filename string
   745  		disposition := res.Header.Get("Content-Disposition")
   746  		parts := strings.SplitN(disposition, "filename", 2)
   747  		if len(parts) == 2 {
   748  			filename = strings.SplitN(parts[1], ";", 2)[0]
   749  			filename = strings.TrimSpace(filename)
   750  			filename = strings.Trim(filename, "=\"")
   751  		}
   752  		if len(filename) < 1 {
   753  			_, filename = path.Split(req.URL.Path)
   754  		}
   755  		if len(filename) < 1 {
   756  			filename = "index.html"
   757  		}
   758  		savepath = filepath.Join(saveto, filename)
   759  	}
   760  	file, err := os.OpenFile(savepath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModePerm)
   761  	if err == nil {
   762  		defer file.Close()
   763  		saved, err = io.Copy(file, res.Body)
   764  	}
   765  	return
   766  }
   767  
   768  type ShouldClient struct {
   769  	Shoulder xmap.Shoulder
   770  	Client   *Client
   771  }
   772  
   773  func NewShouldClient() (client *ShouldClient) {
   774  	client = &ShouldClient{
   775  		Client: Shared,
   776  	}
   777  	return
   778  }
   779  
   780  //Should will assert by xmap.M.Should
   781  func (c *ShouldClient) Should(t *testing.T, args ...interface{}) *ShouldClient {
   782  	c.Shoulder.Should(t, args...)
   783  	return c
   784  }
   785  
   786  //ShouldError will assert err is not nil
   787  func (c *ShouldClient) ShouldError(t *testing.T) *ShouldClient {
   788  	c.Shoulder.ShouldError(t)
   789  	return c
   790  }
   791  
   792  //OnlyLog will only show error log
   793  func (c *ShouldClient) OnlyLog(only bool) *ShouldClient {
   794  	c.Shoulder.OnlyLog(only)
   795  	return c
   796  }
   797  
   798  //GetMap will get map from remote
   799  func (c *ShouldClient) GetMap(format string, args ...interface{}) (data xmap.M, err error) {
   800  	data, err = c.Client.GetMap(format, args...)
   801  	c.Shoulder.Valid(3, data, err)
   802  	return
   803  }
   804  
   805  //GetHeaderMap will get map from remote
   806  func (c *ShouldClient) GetHeaderMap(header xmap.M, format string, args ...interface{}) (data xmap.M, res *http.Response, err error) {
   807  	data, res, err = c.Client.GetHeaderMap(header, format, args...)
   808  	c.Shoulder.Valid(3, data, err)
   809  	return
   810  }
   811  
   812  //PostMap will get map from remote
   813  func (c *ShouldClient) PostMap(body io.Reader, format string, args ...interface{}) (data xmap.M, err error) {
   814  	data, err = c.Client.PostMap(body, format, args...)
   815  	c.Shoulder.Valid(3, data, err)
   816  	return
   817  }
   818  
   819  //PostTypeMap will get map from remote
   820  func (c *ShouldClient) PostTypeMap(contentType string, body io.Reader, format string, args ...interface{}) (data xmap.M, err error) {
   821  	data, err = c.Client.PostTypeMap(contentType, body, format, args...)
   822  	c.Shoulder.Valid(3, data, err)
   823  	return
   824  }
   825  
   826  //PostHeaderMap will get map from remote
   827  func (c *ShouldClient) PostHeaderMap(header xmap.M, body io.Reader, format string, args ...interface{}) (data xmap.M, res *http.Response, err error) {
   828  	data, res, err = c.Client.PostHeaderMap(header, body, format, args...)
   829  	c.Shoulder.Valid(3, data, err)
   830  	return
   831  }
   832  
   833  //PostJSONMap will get map from remote
   834  func (c *ShouldClient) PostJSONMap(body interface{}, format string, args ...interface{}) (data xmap.M, err error) {
   835  	data, err = c.Client.PostJSONMap(body, format, args...)
   836  	c.Shoulder.Valid(3, data, err)
   837  	return
   838  }
   839  
   840  //MethodBytes will do http request, read reponse and parse to map
   841  func (c *ShouldClient) MethodMap(method string, header xmap.M, body io.Reader, format string, args ...interface{}) (data xmap.M, res *http.Response, err error) {
   842  	data, res, err = c.Client.MethodMap(method, header, body, format, args...)
   843  	c.Shoulder.Valid(3, data, err)
   844  	return
   845  }
   846  
   847  //PostFormMap will get map from remote
   848  func (c *ShouldClient) PostFormMap(form xmap.M, format string, args ...interface{}) (data xmap.M, err error) {
   849  	data, err = c.Client.PostFormMap(form, format, args...)
   850  	c.Shoulder.Valid(3, data, err)
   851  	return
   852  }
   853  
   854  //PostMultipartMap will get map from remote
   855  func (c *ShouldClient) PostMultipartMap(header, fields xmap.M, format string, args ...interface{}) (data xmap.M, err error) {
   856  	data, err = c.Client.PostMultipartMap(header, fields, format, args...)
   857  	c.Shoulder.Valid(3, data, err)
   858  	return
   859  }
   860  
   861  //UploadMap will get map from remote
   862  func (c *ShouldClient) UploadMap(fields xmap.M, filekey, filename, format string, args ...interface{}) (data xmap.M, err error) {
   863  	data, err = c.Client.UploadMap(fields, filekey, filename, format, args...)
   864  	c.Shoulder.Valid(3, data, err)
   865  	return
   866  }