host_style_bucket.go 1.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354
  1. package s3
  2. import (
  3. "regexp"
  4. "strings"
  5. "github.com/aws/aws-sdk-go/aws"
  6. "github.com/aws/aws-sdk-go/aws/awsutil"
  7. "github.com/aws/aws-sdk-go/aws/request"
  8. )
  9. var reDomain = regexp.MustCompile(`^[a-z0-9][a-z0-9\.\-]{1,61}[a-z0-9]$`)
  10. var reIPAddress = regexp.MustCompile(`^(\d+\.){3}\d+$`)
  11. // dnsCompatibleBucketName returns true if the bucket name is DNS compatible.
  12. // Buckets created outside of the classic region MUST be DNS compatible.
  13. func dnsCompatibleBucketName(bucket string) bool {
  14. return reDomain.MatchString(bucket) &&
  15. !reIPAddress.MatchString(bucket) &&
  16. !strings.Contains(bucket, "..")
  17. }
  18. // hostStyleBucketName returns true if the request should put the bucket in
  19. // the host. This is false if S3ForcePathStyle is explicitly set or if the
  20. // bucket is not DNS compatible.
  21. func hostStyleBucketName(r *request.Request, bucket string) bool {
  22. if aws.BoolValue(r.Service.Config.S3ForcePathStyle) {
  23. return false
  24. }
  25. // Bucket might be DNS compatible but dots in the hostname will fail
  26. // certificate validation, so do not use host-style.
  27. if r.HTTPRequest.URL.Scheme == "https" && strings.Contains(bucket, ".") {
  28. return false
  29. }
  30. // Use host-style if the bucket is DNS compatible
  31. return dnsCompatibleBucketName(bucket)
  32. }
  33. func updateHostWithBucket(r *request.Request) {
  34. b := awsutil.ValuesAtPath(r.Params, "Bucket")
  35. if len(b) == 0 {
  36. return
  37. }
  38. if bucket := b[0].(string); bucket != "" && hostStyleBucketName(r, bucket) {
  39. r.HTTPRequest.URL.Host = bucket + "." + r.HTTPRequest.URL.Host
  40. r.HTTPRequest.URL.Path = strings.Replace(r.HTTPRequest.URL.Path, "/{Bucket}", "", -1)
  41. if r.HTTPRequest.URL.Path == "" {
  42. r.HTTPRequest.URL.Path = "/"
  43. }
  44. }
  45. }