func httpDownload()

in agent/fileutil/artifact/artifact.go [60:147]


func httpDownload(ctx context.T, fileURL string, destFile string, expectedBucketOwner string) (output DownloadOutput, err error) {
	log := ctx.Log()
	log.Debugf("attempting to download as http/https download from %v to %v", fileURL, destFile)

	exponentialBackoff, err := backoffconfig.GetExponentialBackoff(200*time.Millisecond, 5)
	if err != nil {
		return
	}

	download := func() (err error) {
		eTagFile := destFile + ".etag"
		var check http.Client
		var httpRequest *http.Request
		httpRequest, err = http.NewRequest("GET", fileURL, nil)
		if err != nil {
			return
		}
		if fileutil.Exists(destFile) == true && fileutil.Exists(eTagFile) == true {
			log.Debugf("destFile exists at %v, etag file exists at %v", destFile, eTagFile)
			var existingETag string
			existingETag, err = fileutil.ReadAllText(eTagFile)
			httpRequest.Header.Add("If-None-Match", existingETag)

			expectedBucketOwner = strings.TrimSpace(expectedBucketOwner)
			if expectedBucketOwner != "" {
				httpRequest.Header.Add("x-amz-expected-bucket-owner", expectedBucketOwner)
			}
		}
		customTransport := network.GetDefaultTransport(log, ctx.AppConfig())
		customTransport.TLSHandshakeTimeout = 20 * time.Second
		check = http.Client{
			CheckRedirect: func(r *http.Request, via []*http.Request) error {
				r.URL.Opaque = r.URL.Path
				return nil
			},
			Transport: customTransport,
		}

		var resp *http.Response
		resp, err = check.Do(httpRequest)
		if err != nil {
			log.Debugf("failed to download from http/https: %v", err)
			_ = fileutil.DeleteFile(destFile)
			_ = fileutil.DeleteFile(eTagFile)
			return
		}

		if resp.StatusCode == http.StatusNotModified {
			log.Debugf("Unchanged file.")
			output.IsUpdated = false
			output.LocalFilePath = destFile
			return nil
		} else if resp.StatusCode != http.StatusOK {
			_ = fileutil.DeleteFile(destFile)
			_ = fileutil.DeleteFile(eTagFile)
			log.Debugf("failed to download from http/https: %v", err)
			err = fmt.Errorf("http request failed. status:%v statuscode:%v", resp.Status, resp.StatusCode)
			// skip backoff logic if permission denied to the URL
			if resp.StatusCode == http.StatusForbidden {
				return &backoff.PermanentError{Err: err}
			}
			return
		}

		defer resp.Body.Close()
		eTagValue := resp.Header.Get("Etag")
		if eTagValue != "" {
			log.Debug("file eTagValue is ", eTagValue)
			err = fileutil.WriteAllText(eTagFile, eTagValue)
			if err != nil {
				_ = log.Errorf("failed to write eTagfile %v, %v ", eTagFile, err)
				return
			}
		}
		_, err = FileCopy(log, destFile, resp.Body)
		if err == nil {
			output.LocalFilePath = destFile
			output.IsUpdated = true
		} else {
			_ = log.Errorf("failed to write destFile %v, %v ", destFile, err)
		}

		return
	}

	err = backoff.Retry(download, exponentialBackoff)
	return
}