code.cloudfoundry.org/cli@v7.1.0+incompatible/cf/util/downloader/file_download.go (about) 1 package downloader 2 3 import ( 4 "code.cloudfoundry.org/cli/util" 5 "fmt" 6 "io" 7 "net/http" 8 "os" 9 "path/filepath" 10 "strings" 11 ) 12 13 type Downloader interface { 14 DownloadFile(string) (int64, string, error) 15 RemoveFile() error 16 SavePath() string 17 } 18 19 type downloader struct { 20 saveDir string 21 filename string 22 downloaded bool 23 } 24 25 func NewDownloader(saveDir string) Downloader { 26 return &downloader{ 27 saveDir: saveDir, 28 downloaded: false, 29 } 30 } 31 32 //this func returns byte written, filename and error 33 func (d *downloader) DownloadFile(url string) (int64, string, error) { 34 c := http.Client{ 35 Transport: &http.Transport{ 36 TLSClientConfig: util.NewTLSConfig(nil, false), 37 }, 38 CheckRedirect: func(r *http.Request, via []*http.Request) error { 39 r.URL.Opaque = r.URL.Path 40 41 //some redirect return '/' as url 42 if strings.Trim(r.URL.Opaque, "/") != "" { 43 url = r.URL.Opaque 44 } 45 46 return nil 47 }, 48 } 49 50 r, err := c.Get(url) 51 52 if err != nil { 53 return 0, "", err 54 } 55 defer r.Body.Close() 56 57 if r.StatusCode == 200 { 58 d.filename = getFilenameFromHeader(r.Header.Get("Content-Disposition")) 59 60 if d.filename == "" { 61 d.filename = getFilenameFromURL(url) 62 } 63 64 f, err := os.Create(filepath.Join(d.saveDir, d.filename)) 65 if err != nil { 66 return 0, "", err 67 } 68 defer f.Close() 69 70 size, err := io.Copy(f, r.Body) 71 if err != nil { 72 return 0, "", err 73 } 74 75 d.downloaded = true 76 return size, d.filename, nil 77 78 } 79 return 0, "", fmt.Errorf("Error downloading file from %s", url) 80 } 81 82 func (d *downloader) RemoveFile() error { 83 if !d.downloaded { 84 return nil 85 } 86 d.downloaded = false 87 return os.Remove(filepath.Join(d.saveDir, d.filename)) 88 } 89 90 func getFilenameFromHeader(h string) string { 91 if h == "" { 92 return "" 93 } 94 95 contents := strings.Split(h, ";") 96 for _, content := range contents { 97 if strings.Contains(content, "filename=") { 98 content = strings.TrimSpace(content) 99 name := strings.TrimLeft(content, "filename=") 100 return strings.Trim(name, `"`) 101 } 102 } 103 104 return "" 105 } 106 107 func getFilenameFromURL(url string) string { 108 tmp := strings.Split(url, "/") 109 token := tmp[len(tmp)-1] 110 111 if i := strings.LastIndex(token, "?"); i != -1 { 112 token = token[i+1:] 113 } 114 115 if i := strings.LastIndex(token, "&"); i != -1 { 116 token = token[i+1:] 117 } 118 119 if i := strings.LastIndex(token, "="); i != -1 { 120 return token[i+1:] 121 } 122 123 return token 124 } 125 126 func (d *downloader) SavePath() string { 127 return d.saveDir 128 }