diff --git a/cmd/get.go b/cmd/get.go index f970ad7..3a31035 100644 --- a/cmd/get.go +++ b/cmd/get.go @@ -100,6 +100,8 @@ type downloadOption struct { MaxAttempts int AcceptPreRelease bool RoundTripper http.RoundTripper + Username string + Password string Magnet bool Force bool Mod int @@ -143,6 +145,8 @@ func (o *downloadOption) addDownloadFlags(flags *pflag.FlagSet) { flags.IntVarP(&o.Thread, "thread", "t", viper.GetInt("thread"), `Download file with multi-threads. It only works when its value is bigger than 1`) flags.BoolVarP(&o.NoProxy, "no-proxy", "", viper.GetBool("no-proxy"), "Indicate no HTTP proxy taken") + flags.StringVarP(&o.Username, "username", "u", "", "The username for the HTTP basic auth") + flags.StringVarP(&o.Password, "password", "p", "", "The password for the HTTP basic auth") } func (o *downloadOption) fetch() (err error) { @@ -322,6 +326,7 @@ func (o *downloadOption) runE(cmd *cobra.Command, args []string) (err error) { downloader.WithoutProxy(o.NoProxy). WithRoundTripper(o.RoundTripper). WithInsecureSkipVerify(o.SkipTLS). + WithBasicAuth(o.Username, o.Password). WithTimeout(o.Timeout) err = downloader.DownloadWithContinue(targetURL, o.Output, o.ContinueAt, -1, 0, o.ShowProgress) } else { @@ -332,6 +337,7 @@ func (o *downloadOption) runE(cmd *cobra.Command, args []string) (err error) { WithoutProxy(o.NoProxy). WithRoundTripper(o.RoundTripper). WithInsecureSkipVerify(o.SkipTLS). + WithBasicAuth(o.Username, o.Password). WithTimeout(o.Timeout) err = downloader.Download(targetURL, o.Output, o.Thread) } diff --git a/pkg/net/http.go b/pkg/net/http.go index 45d9212..3811240 100644 --- a/pkg/net/http.go +++ b/pkg/net/http.go @@ -219,6 +219,7 @@ func DownloadFileWithMultipleThreadKeepParts(targetURL, targetFilePath string, t type ContinueDownloader struct { downloader *HTTPDownloader + UserName, Password string Timeout time.Duration Context context.Context roundTripper http.RoundTripper @@ -261,6 +262,13 @@ func (c *ContinueDownloader) WithTimeout(timeout time.Duration) *ContinueDownloa return c } +// WithBasicAuth sets the basic auth +func (c *ContinueDownloader) WithBasicAuth(username, password string) *ContinueDownloader { + c.UserName = username + c.Password = password + return c +} + // DownloadWithContinue downloads the files continuously func (c *ContinueDownloader) DownloadWithContinue(targetURL, output string, index, continueAt, end int64, showProgress bool) (err error) { c.downloader = &HTTPDownloader{ @@ -270,6 +278,8 @@ func (c *ContinueDownloader) DownloadWithContinue(targetURL, output string, inde NoProxy: c.noProxy, RoundTripper: c.roundTripper, InsecureSkipVerify: c.insecureSkipVerify, + UserName: c.UserName, + Password: c.Password, Context: c.Context, Timeout: c.Timeout, } @@ -293,9 +303,9 @@ func (c *ContinueDownloader) DownloadWithContinue(targetURL, output string, inde return } -// DetectSizeWithRoundTripper returns the size of target resource -func DetectSizeWithRoundTripper(targetURL, output string, showProgress, noProxy, insecureSkipVerify bool, - roundTripper http.RoundTripper, timeout time.Duration) (total int64, rangeSupport bool, err error) { +// DetectSizeWithRoundTripperAndAuth returns the size of target resource +func DetectSizeWithRoundTripperAndAuth(targetURL, output string, showProgress, noProxy, insecureSkipVerify bool, + roundTripper http.RoundTripper, username, password string, timeout time.Duration) (total int64, rangeSupport bool, err error) { downloader := HTTPDownloader{ TargetFilePath: output, URL: targetURL, @@ -303,6 +313,8 @@ func DetectSizeWithRoundTripper(targetURL, output string, showProgress, noProxy, RoundTripper: roundTripper, NoProxy: false, // below HTTP request does not need proxy InsecureSkipVerify: insecureSkipVerify, + UserName: username, + Password: password, Timeout: timeout, } @@ -331,6 +343,13 @@ func DetectSizeWithRoundTripper(targetURL, output string, showProgress, noProxy, return } +// DetectSizeWithRoundTripper returns the size of target resource +// Deprecated, use DetectSizeWithRoundTripperAndAuth instead +func DetectSizeWithRoundTripper(targetURL, output string, showProgress, noProxy, insecureSkipVerify bool, + roundTripper http.RoundTripper, timeout time.Duration) (total int64, rangeSupport bool, err error) { + return DetectSizeWithRoundTripperAndAuth(targetURL, output, showProgress, noProxy, insecureSkipVerify, roundTripper, "", "", timeout) +} + // ParseSuggestedFilename parse the filename from resp header,More details from https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition func ParseSuggestedFilename(header http.Header, filepath string) (filename string) { if disposition, ok := header["Content-Disposition"]; ok && len(disposition) >= 1 { diff --git a/pkg/net/multi_thread.go b/pkg/net/multi_thread.go index 273a6d0..a69ec34 100644 --- a/pkg/net/multi_thread.go +++ b/pkg/net/multi_thread.go @@ -16,9 +16,10 @@ type MultiThreadDownloader struct { keepParts, showProgress bool insecureSkipVerify bool - roundTripper http.RoundTripper - suggestedFilename string - timeout time.Duration + username, password string + roundTripper http.RoundTripper + suggestedFilename string + timeout time.Duration } // GetSuggestedFilename returns the suggested filename @@ -62,13 +63,20 @@ func (d *MultiThreadDownloader) WithRoundTripper(roundTripper http.RoundTripper) return d } +// WithBasicAuth sets the basic auth +func (d *MultiThreadDownloader) WithBasicAuth(username, password string) *MultiThreadDownloader { + d.username = username + d.password = password + return d +} + // Download starts to download the target URL func (d *MultiThreadDownloader) Download(targetURL, targetFilePath string, thread int) (err error) { // get the total size of the target file var total int64 var rangeSupport bool - if total, rangeSupport, err = DetectSizeWithRoundTripper(targetURL, targetFilePath, d.showProgress, - d.noProxy, d.insecureSkipVerify, d.roundTripper, d.timeout); rangeSupport && err != nil { + if total, rangeSupport, err = DetectSizeWithRoundTripperAndAuth(targetURL, targetFilePath, d.showProgress, + d.noProxy, d.insecureSkipVerify, d.roundTripper, d.username, d.password, d.timeout); rangeSupport && err != nil { return } @@ -120,6 +128,7 @@ func (d *MultiThreadDownloader) Download(targetURL, targetFilePath string, threa downloader.WithoutProxy(d.noProxy). WithRoundTripper(d.roundTripper). WithInsecureSkipVerify(d.insecureSkipVerify). + WithBasicAuth(d.username, d.password). WithContext(ctx).WithTimeout(d.timeout) if downloadErr := downloader.DownloadWithContinue(targetURL, output, int64(index), start, end, d.showProgress); downloadErr != nil { @@ -173,6 +182,7 @@ func (d *MultiThreadDownloader) Download(targetURL, targetFilePath string, threa downloader.WithRoundTripper(d.roundTripper) downloader.WithInsecureSkipVerify(d.insecureSkipVerify) downloader.WithTimeout(d.timeout) + downloader.WithBasicAuth(d.username, d.password) err = downloader.DownloadWithContinue(targetURL, targetFilePath, -1, 0, 0, true) d.suggestedFilename = downloader.GetSuggestedFilename() }