github.com/mattermosttest/mattermost-server/v5@v5.0.0-20200917143240-9dfa12e121f9/app/download.go (about) 1 // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. 2 // See LICENSE.txt for license information. 3 4 package app 5 6 import ( 7 "io" 8 "io/ioutil" 9 "net/http" 10 "net/url" 11 "time" 12 13 "github.com/mattermost/mattermost-server/v5/model" 14 "github.com/mattermost/mattermost-server/v5/utils" 15 16 "github.com/pkg/errors" 17 ) 18 19 const ( 20 // HTTP_REQUEST_TIMEOUT defines a high timeout for downloading large files 21 // from an external URL to avoid slow connections from failing to install. 22 HTTP_REQUEST_TIMEOUT = 1 * time.Hour 23 ) 24 25 func (a *App) DownloadFromURL(downloadURL string) ([]byte, error) { 26 if !model.IsValidHttpUrl(downloadURL) { 27 return nil, errors.Errorf("invalid url %s", downloadURL) 28 } 29 30 u, err := url.ParseRequestURI(downloadURL) 31 if err != nil { 32 return nil, errors.Errorf("failed to parse url %s", downloadURL) 33 } 34 if !*a.Config().PluginSettings.AllowInsecureDownloadUrl && u.Scheme != "https" { 35 return nil, errors.Errorf("insecure url not allowed %s", downloadURL) 36 } 37 38 client := a.HTTPService().MakeClient(true) 39 client.Timeout = HTTP_REQUEST_TIMEOUT 40 41 var resp *http.Response 42 err = utils.ProgressiveRetry(func() error { 43 resp, err = client.Get(downloadURL) 44 45 if err != nil { 46 return errors.Wrapf(err, "failed to fetch from %s", downloadURL) 47 } 48 49 if !(resp.StatusCode >= 200 && resp.StatusCode < 300) { 50 _, _ = io.Copy(ioutil.Discard, resp.Body) 51 _ = resp.Body.Close() 52 return errors.Errorf("failed to fetch from %s", downloadURL) 53 } 54 55 return nil 56 }) 57 if err != nil { 58 return nil, errors.Wrap(err, "download failed after multiple retries.") 59 } 60 61 defer resp.Body.Close() 62 63 return ioutil.ReadAll(resp.Body) 64 }