Skip to content

Commit

Permalink
check detectors and relative paths before proto
Browse files Browse the repository at this point in the history
When checking for an unexpected protocol switch via X-Terraform-Get, we
first must run the configured detectors and check for a relative request
path, since X-Terraform-Get is not required to return a valid URL.
  • Loading branch information
jbardin committed Jun 7, 2022
1 parent c5e9d08 commit 35a9e31
Showing 1 changed file with 53 additions and 33 deletions.
86 changes: 53 additions & 33 deletions get_http.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"net/url"
"os"
"path/filepath"
"regexp"
"strings"
"time"

Expand Down Expand Up @@ -293,50 +294,66 @@ func (g *HttpGetter) Get(dst string, u *url.URL) error {
// If there is a subdir component, then we download the root separately
// into a temporary directory, then copy over the proper subdir.
source, subDir := SourceDirSubdir(source)
if subDir == "" {
var opts []ClientOption
if subDir != "" {
// We have a subdir, time to jump some hoops
return g.getSubdir(ctx, dst, source, subDir)
}

var opts []ClientOption

// Check if the protocol was switched to one which was not configured.
if g.client != nil && g.client.Getters != nil {
// We must first use the Detectors provided, because `X-Terraform-Get does
// not necessarily return a valid URL. We can replace the source string
// here, since the detectors would have been called immediately during the
// next Get anyway.
source, err = Detect(source, g.client.Pwd, g.client.Detectors)
if err != nil {
return err
}

protocol := ""
// X-Terraform-Get allows paths relative to the previous request too,
// which won't have a protocol.
if !relativeGet(source) {
protocol = strings.Split(source, ":")[0]
}

// Check if the protocol was switched to one which was not configured.
//
// Otherwise, all default getters are allowed.
if g.client != nil && g.client.Getters != nil {
protocol := strings.Split(source, ":")[0]
if protocol != "" {
_, allowed := g.client.Getters[protocol]
if !allowed {
return fmt.Errorf("no getter available for X-Terraform-Get source protocol: %q", protocol)
}
}
}

// Add any getter client options.
if g.client != nil {
opts = g.client.Options
}

// If the client is nil, we know we're using the HttpGetter directly. In this case,
// we don't know exactly which protocols are configued, but we can make a good guess.
//
// This prevents all default getters from being allowed when only using the
// HttpGetter directly. To enable protocol switching, a client "wrapper" must
// be used.
if g.client == nil {
opts = append(opts, WithGetters(map[string]Getter{
"http": g,
"https": g,
}))
}

// Ensure we pass along the context we constructed in this function.
//
// This is especially important to enforce a limit on X-Terraform-Get redirects
// which could be setup, if configured, at the top of this function.
opts = append(opts, WithContext(ctx))
// Add any getter client options.
if g.client != nil {
opts = g.client.Options
}

// Note: this allows the protocol to be switched to another configured getters.
return Get(dst, source, opts...)
// If the client is nil, we know we're using the HttpGetter directly. In this case,
// we don't know exactly which protocols are configued, but we can make a good guess.
//
// This prevents all default getters from being allowed when only using the
// HttpGetter directly. To enable protocol switching, a client "wrapper" must
// be used.
if g.client == nil {
opts = append(opts, WithGetters(map[string]Getter{
"http": g,
"https": g,
}))
}

// We have a subdir, time to jump some hoops
return g.getSubdir(ctx, dst, source, subDir)
// Ensure we pass along the context we constructed in this function.
//
// This is especially important to enforce a limit on X-Terraform-Get redirects
// which could be setup, if configured, at the top of this function.
opts = append(opts, WithContext(ctx))

// Note: this allows the protocol to be switched to another configured getters.
return Get(dst, source, opts...)
}

// GetFile fetches the file from src and stores it at dst.
Expand Down Expand Up @@ -566,6 +583,9 @@ func (g *HttpGetter) parseMeta(ctx context.Context, r io.Reader) (string, error)
}
}

// X-Terraform-Get allows paths relative to the previous request
var relativeGet = regexp.MustCompile(`^\.{0,2}/`).MatchString

// attrValue returns the attribute value for the case-insensitive key
// `name', or the empty string if nothing is found.
func attrValue(attrs []xml.Attr, name string) string {
Expand Down

0 comments on commit 35a9e31

Please sign in to comment.