diff --git a/builtin/httpdownloader/downloader/downloader.go b/builtin/httpdownloader/downloader/downloader.go index a597bb37c..dfcdfbcb5 100644 --- a/builtin/httpdownloader/downloader/downloader.go +++ b/builtin/httpdownloader/downloader/downloader.go @@ -1,21 +1,38 @@ package downloader import ( + "bytes" "io/ioutil" "net/http" "os" + "github.com/hashicorp/go-retryablehttp" "github.com/hashicorp/vagrant-plugin-sdk/component" ) +// Type is an enum of all the available http methods +type HTTPMethod int64 + +const ( + GET HTTPMethod = iota + DELETE + HEAD + POST + PUT +) + type Downloader struct { config DownloaderConfig } type DownloaderConfig struct { - Src string - Dest string - Headers http.Header + Dest string + Headers http.Header + Method HTTPMethod + RetryCount int + RequestBody []byte + Src string + UrlQueryParams map[string]string } // Config implements Configurable @@ -28,15 +45,49 @@ func (d *Downloader) DownloadFunc() interface{} { } func (d *Downloader) Download() (err error) { - client := &http.Client{} - req, err := http.NewRequest("GET", d.config.Src, nil) + client := retryablehttp.NewClient() + client.RetryMax = d.config.RetryCount + var req *retryablehttp.Request + + // Create request with request body if one is provided + if d.config.RequestBody != nil { + req, err = retryablehttp.NewRequest( + d.config.Method.String(), d.config.Src, bytes.NewBuffer(d.config.RequestBody), + ) + if err != nil { + return err + } + } else { + // If no request body is provided then create an empty request + req, err = retryablehttp.NewRequest( + d.config.Method.String(), d.config.Src, nil, + ) + } + + // Add query params if provided + if d.config.UrlQueryParams != nil { + q := req.URL.Query() + for k, v := range d.config.UrlQueryParams { + q.Add(k, v) + } + req.URL.RawQuery = q.Encode() + } + + // Set headers req.Header = d.config.Headers + // Add headers to redirects + client.HTTPClient.CheckRedirect = func(req *http.Request, via []*http.Request) error { + for key, val := range via[0].Header { + req.Header[key] = val + } + return err + } + resp, err := client.Do(req) if err != nil { return err } defer resp.Body.Close() - data, err := ioutil.ReadAll(resp.Body) if err != nil { return err diff --git a/builtin/httpdownloader/downloader/httpmethod_string.go b/builtin/httpdownloader/downloader/httpmethod_string.go new file mode 100644 index 000000000..5eda8a71a --- /dev/null +++ b/builtin/httpdownloader/downloader/httpmethod_string.go @@ -0,0 +1,27 @@ +// Code generated by "stringer -type=HTTPMethod -linecomment ./downloader"; DO NOT EDIT. + +package downloader + +import "strconv" + +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[GET-0] + _ = x[DELETE-1] + _ = x[HEAD-2] + _ = x[POST-3] + _ = x[PUT-4] +} + +const _HTTPMethod_name = "GETDELETEHEADPOSTPUT" + +var _HTTPMethod_index = [...]uint8{0, 3, 9, 13, 17, 20} + +func (i HTTPMethod) String() string { + if i < 0 || i >= HTTPMethod(len(_HTTPMethod_index)-1) { + return "HTTPMethod(" + strconv.FormatInt(int64(i), 10) + ")" + } + return _HTTPMethod_name[_HTTPMethod_index[i]:_HTTPMethod_index[i+1]] +} diff --git a/builtin/httpdownloader/main.go b/builtin/httpdownloader/main.go index 7dfbf1f7f..34385401d 100644 --- a/builtin/httpdownloader/main.go +++ b/builtin/httpdownloader/main.go @@ -5,7 +5,7 @@ import ( "github.com/hashicorp/vagrant/builtin/httpdownloader/downloader" ) -//go:generate protoc -I ../../.. --go_opt=plugins=grpc --go_out=../../.. vagrant-ruby/builtin/httpdownloader/proto/plugin.proto +//go:generate stringer -type=HTTPMethod -linecomment ./downloader var PluginOptions = []sdk.Option{ sdk.WithComponents( diff --git a/internal/plugin/manager.go b/internal/plugin/manager.go index 7a12ce9a4..cd42bf409 100644 --- a/internal/plugin/manager.go +++ b/internal/plugin/manager.go @@ -35,6 +35,7 @@ var ( component.MapperType, component.PluginInfoType, component.PushType, + component.DownloaderType, } ) diff --git a/internal/plugin/plugin.go b/internal/plugin/plugin.go index 092d092ac..c27f8d398 100644 --- a/internal/plugin/plugin.go +++ b/internal/plugin/plugin.go @@ -15,7 +15,7 @@ import ( "github.com/hashicorp/vagrant-plugin-sdk/core" "github.com/hashicorp/vagrant-plugin-sdk/internal-shared/cacher" "github.com/hashicorp/vagrant-plugin-sdk/internal-shared/cleanup" - "github.com/hashicorp/vagrant/builtin/filedownloader" + "github.com/hashicorp/vagrant/builtin/httpdownloader" "github.com/hashicorp/vagrant/builtin/myplugin" "github.com/hashicorp/vagrant/builtin/otherplugin" ) @@ -34,7 +34,7 @@ var ( Builtins = map[string][]sdk.Option{ "myplugin": myplugin.CommandOptions, "otherplugin": otherplugin.CommandOptions, - "filedownloader": filedownloader.PluginOptions, + "httpdownloader": httpdownloader.PluginOptions, } )