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 }