Skip to content

Commit 35a9e31

Browse files
committed
check detectors and relative paths before proto
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.
1 parent c5e9d08 commit 35a9e31

File tree

1 file changed

+53
-33
lines changed

1 file changed

+53
-33
lines changed

get_http.go

Lines changed: 53 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"net/url"
1111
"os"
1212
"path/filepath"
13+
"regexp"
1314
"strings"
1415
"time"
1516

@@ -293,50 +294,66 @@ func (g *HttpGetter) Get(dst string, u *url.URL) error {
293294
// If there is a subdir component, then we download the root separately
294295
// into a temporary directory, then copy over the proper subdir.
295296
source, subDir := SourceDirSubdir(source)
296-
if subDir == "" {
297-
var opts []ClientOption
297+
if subDir != "" {
298+
// We have a subdir, time to jump some hoops
299+
return g.getSubdir(ctx, dst, source, subDir)
300+
}
301+
302+
var opts []ClientOption
303+
304+
// Check if the protocol was switched to one which was not configured.
305+
if g.client != nil && g.client.Getters != nil {
306+
// We must first use the Detectors provided, because `X-Terraform-Get does
307+
// not necessarily return a valid URL. We can replace the source string
308+
// here, since the detectors would have been called immediately during the
309+
// next Get anyway.
310+
source, err = Detect(source, g.client.Pwd, g.client.Detectors)
311+
if err != nil {
312+
return err
313+
}
314+
315+
protocol := ""
316+
// X-Terraform-Get allows paths relative to the previous request too,
317+
// which won't have a protocol.
318+
if !relativeGet(source) {
319+
protocol = strings.Split(source, ":")[0]
320+
}
298321

299-
// Check if the protocol was switched to one which was not configured.
300-
//
301322
// Otherwise, all default getters are allowed.
302-
if g.client != nil && g.client.Getters != nil {
303-
protocol := strings.Split(source, ":")[0]
323+
if protocol != "" {
304324
_, allowed := g.client.Getters[protocol]
305325
if !allowed {
306326
return fmt.Errorf("no getter available for X-Terraform-Get source protocol: %q", protocol)
307327
}
308328
}
329+
}
309330

310-
// Add any getter client options.
311-
if g.client != nil {
312-
opts = g.client.Options
313-
}
314-
315-
// If the client is nil, we know we're using the HttpGetter directly. In this case,
316-
// we don't know exactly which protocols are configued, but we can make a good guess.
317-
//
318-
// This prevents all default getters from being allowed when only using the
319-
// HttpGetter directly. To enable protocol switching, a client "wrapper" must
320-
// be used.
321-
if g.client == nil {
322-
opts = append(opts, WithGetters(map[string]Getter{
323-
"http": g,
324-
"https": g,
325-
}))
326-
}
327-
328-
// Ensure we pass along the context we constructed in this function.
329-
//
330-
// This is especially important to enforce a limit on X-Terraform-Get redirects
331-
// which could be setup, if configured, at the top of this function.
332-
opts = append(opts, WithContext(ctx))
331+
// Add any getter client options.
332+
if g.client != nil {
333+
opts = g.client.Options
334+
}
333335

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

338-
// We have a subdir, time to jump some hoops
339-
return g.getSubdir(ctx, dst, source, subDir)
349+
// Ensure we pass along the context we constructed in this function.
350+
//
351+
// This is especially important to enforce a limit on X-Terraform-Get redirects
352+
// which could be setup, if configured, at the top of this function.
353+
opts = append(opts, WithContext(ctx))
354+
355+
// Note: this allows the protocol to be switched to another configured getters.
356+
return Get(dst, source, opts...)
340357
}
341358

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

586+
// X-Terraform-Get allows paths relative to the previous request
587+
var relativeGet = regexp.MustCompile(`^\.{0,2}/`).MatchString
588+
569589
// attrValue returns the attribute value for the case-insensitive key
570590
// `name', or the empty string if nothing is found.
571591
func attrValue(attrs []xml.Attr, name string) string {

0 commit comments

Comments
 (0)