Fix check for bucket name: (#3832)

* Do not allow bucket names with adjacent hypen and periods.
* Improve performance by eliminating the usage of regular expressions.
This commit is contained in:
Aditya Manthramurthy 2017-03-03 23:53:41 +05:30 committed by Harshavardhana
parent 6c00a57a7c
commit 6df7bc42b8
2 changed files with 49 additions and 17 deletions

View file

@ -21,7 +21,6 @@ import (
"fmt"
"io"
"path"
"regexp"
"runtime"
"strings"
"unicode/utf8"
@ -38,12 +37,10 @@ const (
minioMetaMultipartBucket = minioMetaBucket + "/" + mpartMetaPrefix
// Minio Tmp meta prefix.
minioMetaTmpBucket = minioMetaBucket + "/tmp"
// DNS separator (period), used for bucket name validation.
dnsDelimiter = "."
)
// validBucket regexp.
var validBucket = regexp.MustCompile(`^[a-z0-9][a-z0-9\.\-]{1,61}[a-z0-9]$`)
var isIPAddress = regexp.MustCompile(`^(\d+\.){3}\d+$`)
// isMinioBucket returns true if given bucket is a Minio internal
// bucket and false otherwise.
func isMinioMetaBucketName(bucket string) bool {
@ -52,10 +49,13 @@ func isMinioMetaBucketName(bucket string) bool {
bucket == minioMetaTmpBucket
}
// IsValidBucketName verifies a bucket name in accordance with Amazon's
// requirements. It must be 3-63 characters long, can contain dashes
// and periods, but must begin and end with a lowercase letter or a number.
// See: http://docs.aws.amazon.com/AmazonS3/latest/dev/BucketRestrictions.html
// IsValidBucketName verifies that a bucket name is in accordance with
// Amazon's requirements (i.e. DNS naming conventions). It must be 3-63
// characters long, and it must be a sequence of one or more labels
// separated by periods. Each label can contain lowercase ascii
// letters, decimal digits and hyphens, but must not begin or end with
// a hyphen. See:
// http://docs.aws.amazon.com/AmazonS3/latest/dev/BucketRestrictions.html
func IsValidBucketName(bucket string) bool {
// Special case when bucket is equal to one of the meta buckets.
if isMinioMetaBucketName(bucket) {
@ -64,12 +64,39 @@ func IsValidBucketName(bucket string) bool {
if len(bucket) < 3 || len(bucket) > 63 {
return false
}
if bucket[0] == '.' || bucket[len(bucket)-1] == '.' {
return false
// Split on dot and check each piece conforms to rules.
allNumbers := true
pieces := strings.Split(bucket, dnsDelimiter)
for _, piece := range pieces {
if len(piece) == 0 || piece[0] == '-' ||
piece[len(piece)-1] == '-' {
// Current piece has 0-length or starts or
// ends with a hyphen.
return false
}
// Now only need to check if each piece is a valid
// 'label' in AWS terminology and if the bucket looks
// like an IP address.
isNotNumber := false
for i := 0; i < len(piece); i++ {
switch {
case (piece[i] >= 'a' && piece[i] <= 'z' ||
piece[i] == '-'):
// Found a non-digit character, so
// this piece is not a number.
isNotNumber = true
case piece[i] >= '0' && piece[i] <= '9':
// Nothing to do.
default:
// Found invalid character.
return false
}
}
allNumbers = allNumbers && !isNotNumber
}
return (validBucket.MatchString(bucket) &&
!isIPAddress.MatchString(bucket) &&
!strings.Contains(bucket, ".."))
// Does the bucket name look like an IP address?
return !(len(pieces) == 4 && allNumbers)
}
// IsValidObjectName verifies an object name in accordance with Amazon's

View file

@ -41,6 +41,8 @@ func TestIsValidBucketName(t *testing.T) {
{"testbucket", true},
{"1bucket", true},
{"bucket1", true},
{"a.b", true},
{"ab.a.bc", true},
// cases for which test should fail.
// passing invalid bucket names.
{"------", false},
@ -59,11 +61,14 @@ func TestIsValidBucketName(t *testing.T) {
{"ends-with-a-dot.", false},
{"ends-with-a-dash-", false},
{"-starts-with-a-dash", false},
{"THIS-BEINGS-WITH-UPPERCASe", false},
{"THIS-BEGINS-WITH-UPPERCASe", false},
{"tHIS-ENDS-WITH-UPPERCASE", false},
{"ThisBeginsAndEndsWithUpperCase", false},
{"ThisBeginsAndEndsWithUpperCasE", false},
{"una ñina", false},
{"lalalallalallalalalallalallalala-theString-size-is-greater-than-64", false},
{"dash-.may-not-appear-next-to-dot", false},
{"dash.-may-not-appear-next-to-dot", false},
{"dash-.-may-not-appear-next-to-dot", false},
{"lalalallalallalalalallalallalala-thestring-size-is-greater-than-63", false},
}
for i, testCase := range testCases {