1
0
mirror of https://github.com/openshift/source-to-image.git synced 2026-02-06 06:44:58 +01:00
Files
source-to-image/pkg/scripts/download.go
divyansh42 4894b3d40d Improve stacktrace to fix tech debts
Signed-off-by: divyansh42 <diagrawa@redhat.com>
2023-10-30 12:25:34 +05:30

152 lines
4.1 KiB
Go

package scripts
import (
"io"
"net/http"
"net/url"
"os"
"path/filepath"
"sync"
"github.com/openshift/source-to-image/pkg/api"
s2ierr "github.com/openshift/source-to-image/pkg/errors"
"github.com/openshift/source-to-image/pkg/scm/git"
utillog "github.com/openshift/source-to-image/pkg/util/log"
)
var log = utillog.StderrLog
// Downloader downloads the specified URL to the target file location
type Downloader interface {
Download(url *url.URL, target string) (*git.SourceInfo, error)
}
// schemeReader creates an io.Reader from the given url.
type schemeReader interface {
Read(*url.URL) (io.ReadCloser, error)
}
type downloader struct {
schemeReaders map[string]schemeReader
}
// NewDownloader creates an instance of the default Downloader implementation
func NewDownloader(proxyConfig *api.ProxyConfig) Downloader {
httpReader := NewHTTPURLReader(proxyConfig)
return &downloader{
schemeReaders: map[string]schemeReader{
"http": httpReader,
"https": httpReader,
"file": &FileURLReader{},
"image": &ImageReader{},
},
}
}
// Download downloads the file pointed to by URL into local targetFile
// Returns information a boolean flag informing whether any download/copy operation
// happened and an error if there was a problem during that operation
func (d *downloader) Download(url *url.URL, targetFile string) (*git.SourceInfo, error) {
r := d.schemeReaders[url.Scheme]
info := &git.SourceInfo{}
if r == nil {
log.Errorf("No URL handler found for %s", url.String())
return nil, s2ierr.NewURLHandlerError(url.String())
}
reader, err := r.Read(url)
if err != nil {
return nil, err
}
defer reader.Close()
out, err := os.Create(targetFile)
defer out.Close()
if err != nil {
log.Errorf("Unable to create target file %s (%v)", targetFile, err)
return nil, err
}
if _, err = io.Copy(out, reader); err != nil {
os.Remove(targetFile)
log.Warningf("Skipping file %s due to error copying from source: %v", targetFile, err)
return nil, err
}
log.V(2).Infof("Downloaded '%s'", url.String())
info.Location = url.String()
return info, nil
}
// HTTPURLReader retrieves a response from a given HTTP(S) URL.
type HTTPURLReader struct {
Get func(url string) (*http.Response, error)
}
var transportMap map[api.ProxyConfig]*http.Transport
var transportMapMutex sync.Mutex
func init() {
transportMap = make(map[api.ProxyConfig]*http.Transport)
}
// NewHTTPURLReader returns a new HTTPURLReader.
func NewHTTPURLReader(proxyConfig *api.ProxyConfig) *HTTPURLReader {
getFunc := http.Get
if proxyConfig != nil {
transportMapMutex.Lock()
transport, ok := transportMap[*proxyConfig]
if !ok {
transport = &http.Transport{
Proxy: func(req *http.Request) (*url.URL, error) {
if proxyConfig.HTTPSProxy != nil && req.URL.Scheme == "https" {
return proxyConfig.HTTPSProxy, nil
}
return proxyConfig.HTTPProxy, nil
},
}
transportMap[*proxyConfig] = transport
}
transportMapMutex.Unlock()
client := &http.Client{
Transport: transport,
}
getFunc = client.Get
}
return &HTTPURLReader{Get: getFunc}
}
// Read produces an io.Reader from an http(s) URL.
func (h *HTTPURLReader) Read(url *url.URL) (io.ReadCloser, error) {
resp, err := h.Get(url.String())
if err != nil {
if resp != nil {
defer resp.Body.Close()
}
return nil, err
}
if resp.StatusCode == 200 || resp.StatusCode == 201 {
return resp.Body, nil
}
return nil, s2ierr.NewDownloadError(url.String(), resp.StatusCode)
}
// FileURLReader opens a specified file and returns its stream
type FileURLReader struct{}
// Read produces an io.Reader from a file URL
func (*FileURLReader) Read(url *url.URL) (io.ReadCloser, error) {
// for some reason url.Host may contain information about the ./ or ../ when
// specifying relative path, thus using that value as well
return os.Open(filepath.Clean(filepath.Join(url.Host, url.Path)))
}
// ImageReader just returns information the URL is from inside the image
type ImageReader struct{}
// Read throws Not implemented error
func (*ImageReader) Read(url *url.URL) (io.ReadCloser, error) {
return nil, s2ierr.NewScriptsInsideImageError(url.String())
}