diff --git a/download.go b/download.go index 603bad3..ad2e173 100644 --- a/download.go +++ b/download.go @@ -61,60 +61,34 @@ type ( } ) -// GetInfo returns URL info, and error if any. -func (d Download) GetInfo() (*Info, error) { - - req, err := NewRequest(d.ctx, "HEAD", d.URL, d.Header) - - if err != nil { - return nil, err - } - - if res, err := d.Client.Do(req); err == nil && res.StatusCode == http.StatusOK { - - return &Info{ - Size: uint64(res.ContentLength), - Name: getNameFromHeader(res.Header.Get("content-disposition")), - Rangeable: res.Header.Get("accept-ranges") == "bytes", - }, nil - } - - return &Info{}, nil -} - -// getInfoFromGetRequest download the first byte of the file, to get content length in -// case of HEAD request not supported, and if partial content not supported so this will download the -// file in one chunk. it returns *Info, and error if any. -func (d *Download) getInfoFromGetRequest() (*Info, error) { +// Try downloading the first byte of the file using a range request. +// If the server supports range requests, then we'll extract the length info from content-range, +// Otherwise this just downloads the whole file in one go +func (d *Download) GetInfoOrDownload() (*Info, error) { var ( - err error - req *http.Request - res *http.Response + err error + dest *os.File + req *http.Request + res *http.Response ) - if req, err = NewRequest(d.ctx, "GET", d.URL, d.Header); err != nil { + if req, err = NewRequest(d.ctx, "GET", d.URL, append(d.Header, GotHeader{"Range", "bytes=0-0"})); err != nil { return nil, err } - req.Header.Set("Range", "bytes=0-1") - if res, err = d.Client.Do(req); err != nil { return nil, err } - defer res.Body.Close() if res.StatusCode >= 300 { return nil, fmt.Errorf("Response status code is not ok: %d", res.StatusCode) } - dest, err := os.Create(d.Name()) - - if err != nil { + if dest, err = os.Create(d.Name()); err != nil { return nil, err } - defer dest.Close() if _, err = io.Copy(dest, io.TeeReader(res.Body, d)); err != nil { @@ -122,8 +96,8 @@ func (d *Download) getInfoFromGetRequest() (*Info, error) { } // Get content length from content-range response header, - // if content-range exists, that's mean partial content is supported. - if cr := res.Header.Get("content-range"); cr != "" && res.ContentLength == 2 { + // if content-range exists, that means partial content is supported. + if cr := res.Header.Get("content-range"); cr != "" && res.ContentLength == 1 { l := strings.Split(cr, "/") if len(l) == 2 { if length, err := strconv.ParseUint(l[1], 10, 64); err == nil { @@ -158,22 +132,14 @@ func (d *Download) Init() (err error) { d.ctx = context.Background() } - // Get and set URL size and partial content support state. - if d.info, err = d.GetInfo(); err != nil { + // Get URL info and partial content support state + if d.info, err = d.GetInfoOrDownload(); err != nil { return err } - // Maybe partial content not supported 😢! - if d.info.Rangeable == false || d.info.Size == 0 { - - if d.info, err = d.getInfoFromGetRequest(); err != nil { - return err - } - - // Partial content not supported, and the file downladed. - if d.info.Rangeable == false { - return nil - } + // Partial content not supported, and the file downladed. + if d.info.Rangeable == false { + return nil } // Set concurrency default.