func TestProgressReader(t *testing.T) {
	filename := "progress_test.go"
	f, err := os.Open(filename)
	defer f.Close()
	if err != nil {
		log.Fatalln(err)
	}
	fs, err := os.Stat(filename)
	if err != nil {
		log.Fatalln(err)
	}

	p := New()
	p.Total = fs.Size()
	p.Progress = func(current, total, expected int64) {
		log.Println("Reading", current, total, expected)
		assert.Equal(t, true, current <= total)
	}

	b := new(bytes.Buffer)
	r := syncreader.New(f, p)
	_, err = b.ReadFrom(r)
	if err != nil {
		log.Fatalln(err)
	}
	assert.Equal(t, fs.Size(), int64(b.Len()))
}
func (r *Requester) Do() (*bytes.Buffer, error) {
	// lazy create request
	r.req = &http.Request{
		Method: r.Method,
		URL:    r.Url,
		Header: r.Header,
	}

	// uploading before
	if r.IsUpload {
		fields, _ := r.rawBody.(map[string]string)
		r.Form(r.files, fields)
	}

	if len(r.cookies) > 0 {
		for _, c := range r.cookies {
			r.req.AddCookie(c)
		}
	}

	// pack body
	r.packBody()

	// uploading after
	if r.IsUpload && r.pg != nil {
		r.pg.Total = r.Length
		r.Body = ioutil.NopCloser(syncreader.New(r.Body, r.pg))
	}

	if r.Body != nil {
		if r.Header.Get("Content-Type") == "" {
			r.Header.Set("Content-Type", "application/x-www-form-urlencoded")
		}
		r.req.Body = r.Body
		if r.Length > 0 {
			r.req.ContentLength = r.Length
		}
	}

	var (
		res *http.Response
		err error
	)

	switch r.Url.Scheme {
	case "http", "https":
		r.transport = new(http.Transport)
		if r.tlsconfig != nil {
			r.transport.TLSClientConfig = r.tlsconfig
		}
		r.client = &http.Client{Transport: r.transport, Timeout: r.timeout}
		res, err = r.client.Do(r.req)
		if err != nil {
			return nil, err
		}
		break
	default:
		// TODO @fundon, customzie
		conn, err := net.Dial(r.Url.Scheme, r.Url.Host)
		if err != nil {
			return nil, err
		}
		r.clientConn = httputil.NewClientConn(conn, nil)
		res, err = r.clientConn.Do(r.req)
		if err != nil {
			return nil, err
		}
	}

	defer res.Body.Close()

	r.res = res
	r.StatusCode = res.StatusCode
	// hack, return response header
	r.Header = res.Header
	r.Buffer = new(bytes.Buffer)
	dw := io.MultiWriter(r.Buffer)

	// downloading
	if r.IsDownload {
		var fw io.Writer
		switch t := r.destination.(type) {
		case string:
			p, err := filepath.Abs(t)
			if err != nil {
				return nil, err
			}
			f, err := os.Create(p)
			defer f.Close()
			if err != nil {
				return nil, err
			}
			fw = f
			break
		default:
			fw, _ = t.(io.Writer)
		}
		if r.pg != nil {
			r.pg.Total = res.ContentLength
		}
		dw = io.MultiWriter(dw, r.pg, fw)
		if err != nil {
			return nil, err
		}
	}

	_, err = io.Copy(dw, res.Body)
	if err != nil {
		return nil, err
	}
	return r.Buffer, nil
}