diff --git a/cmd/api-errors.go b/cmd/api-errors.go
index 89b791935..e8a9cf46a 100644
--- a/cmd/api-errors.go
+++ b/cmd/api-errors.go
@@ -119,6 +119,7 @@ const (
ErrFilterNamePrefix
ErrFilterNameSuffix
ErrFilterValueInvalid
+ ErrOverlappingConfigs
// S3 extended errors.
ErrContentSHA256Mismatch
@@ -505,6 +506,11 @@ var errorCodeResponse = map[APIErrorCode]APIError{
Description: "Size of filter rule value cannot exceed 1024 bytes in UTF-8 representation",
HTTPStatusCode: http.StatusBadRequest,
},
+ ErrOverlappingConfigs: {
+ Code: "InvalidArgument",
+ Description: "Configurations overlap. Configurations on the same bucket cannot share a common event type.",
+ HTTPStatusCode: http.StatusBadRequest,
+ },
/// S3 extensions.
ErrContentSHA256Mismatch: {
diff --git a/cmd/bucket-notification-datatypes.go b/cmd/bucket-notification-datatypes.go
index 070a4d34c..79532dd22 100644
--- a/cmd/bucket-notification-datatypes.go
+++ b/cmd/bucket-notification-datatypes.go
@@ -32,33 +32,30 @@ type keyFilter struct {
FilterRules []filterRule `xml:"FilterRule,omitempty"`
}
-// Queue SQS configuration.
-type queueConfig struct {
+// Common elements of service notification.
+type serviceConfig struct {
Events []string `xml:"Event"`
Filter struct {
Key keyFilter `xml:"S3Key,omitempty"`
}
- ID string `xml:"Id"`
+ ID string `xml:"Id"`
+}
+
+// Queue SQS configuration.
+type queueConfig struct {
+ serviceConfig
QueueARN string `xml:"Queue"`
}
// Topic SNS configuration, this is a compliance field not used by minio yet.
type topicConfig struct {
- Events []string `xml:"Event"`
- Filter struct {
- Key keyFilter `xml:"S3Key"`
- }
- ID string `xml:"Id"`
+ serviceConfig
TopicARN string `xml:"Topic"`
}
// Lambda function configuration, this is a compliance field not used by minio yet.
type lambdaConfig struct {
- Events []string `xml:"Event"`
- Filter struct {
- Key keyFilter `xml:"S3Key,omitempty"`
- }
- ID string `xml:"Id"`
+ serviceConfig
LambdaARN string `xml:"CloudFunction"`
}
diff --git a/cmd/bucket-notification-utils.go b/cmd/bucket-notification-utils.go
index 3df2d0687..27930440c 100644
--- a/cmd/bucket-notification-utils.go
+++ b/cmd/bucket-notification-utils.go
@@ -266,17 +266,68 @@ func validateTopicConfigs(topicConfigs []topicConfig) APIErrorCode {
return ErrNone
}
+// Check all the queue configs for any duplicates.
+func checkDuplicateQueueConfigs(configs []queueConfig) APIErrorCode {
+ configMaps := make(map[string]int)
+
+ // Navigate through each configs and count the entries.
+ for _, config := range configs {
+ configMaps[config.QueueARN]++
+ }
+
+ // Validate if there are any duplicate counts.
+ for _, count := range configMaps {
+ if count != 1 {
+ return ErrOverlappingConfigs
+ }
+ }
+
+ // Success.
+ return ErrNone
+}
+
+// Check all the topic configs for any duplicates.
+func checkDuplicateTopicConfigs(configs []topicConfig) APIErrorCode {
+ configMaps := make(map[string]int)
+
+ // Navigate through each configs and count the entries.
+ for _, config := range configs {
+ configMaps[config.TopicARN]++
+ }
+
+ // Validate if there are any duplicate counts.
+ for _, count := range configMaps {
+ if count != 1 {
+ return ErrOverlappingConfigs
+ }
+ }
+
+ // Success.
+ return ErrNone
+}
+
// Validates all the bucket notification configuration for their validity,
// if one of the config is malformed or has invalid data it is rejected.
// Configuration is never applied partially.
func validateNotificationConfig(nConfig notificationConfig) APIErrorCode {
+ // Validate all queue configs.
if s3Error := validateQueueConfigs(nConfig.QueueConfigs); s3Error != ErrNone {
return s3Error
}
+ // Validate all topic configs.
if s3Error := validateTopicConfigs(nConfig.TopicConfigs); s3Error != ErrNone {
return s3Error
}
+ // Check for duplicate queue configs.
+ if s3Error := checkDuplicateQueueConfigs(nConfig.QueueConfigs); s3Error != ErrNone {
+ return s3Error
+ }
+ // Check for duplicate topic configs.
+ if s3Error := checkDuplicateTopicConfigs(nConfig.TopicConfigs); s3Error != ErrNone {
+ return s3Error
+ }
+
// Add validation for other configurations.
return ErrNone
}
diff --git a/cmd/server_test.go b/cmd/server_test.go
index 6a3426bd1..78784ba54 100644
--- a/cmd/server_test.go
+++ b/cmd/server_test.go
@@ -75,10 +75,9 @@ func (s *TestSuiteCommon) TestAuth(c *C) {
c.Assert(len(accessID), Equals, minioAccessID)
}
-// TestBucketNotification - Inserts the bucket notification and
-// verifies it by fetching the notification back.
+// TestBucketNotification - Inserts the bucket notification and verifies it by fetching the notification back.
func (s *TestSuiteCommon) TestBucketNotification(c *C) {
- // Sample bucket notification
+ // Sample bucket notification.
bucketNotificationBuf := `s3:ObjectCreated:Putprefiximages/1arn:minio:sns:us-east-1:444455556666:listen`
// generate a random bucket Name.
@@ -100,7 +99,7 @@ func (s *TestSuiteCommon) TestBucketNotification(c *C) {
c.Assert(err, IsNil)
client = http.Client{}
- // execute the HTTP request to create bucket.
+ // execute the HTTP request.
response, err = client.Do(request)
c.Assert(err, IsNil)
@@ -128,7 +127,7 @@ func (s *TestSuiteCommon) TestBucketNotification(c *C) {
c.Assert(err, IsNil)
client = http.Client{}
- // execute the HTTP request to create bucket.
+ // execute the HTTP request.
response, err = client.Do(request)
c.Assert(err, IsNil)
@@ -140,7 +139,7 @@ func (s *TestSuiteCommon) TestBucketNotification(c *C) {
c.Assert(err, IsNil)
client = http.Client{}
- // execute the HTTP request to create bucket.
+ // execute the HTTP request.
response, err = client.Do(request)
c.Assert(err, IsNil)
@@ -152,10 +151,21 @@ func (s *TestSuiteCommon) TestBucketNotification(c *C) {
c.Assert(err, IsNil)
client = http.Client{}
- // execute the HTTP request to create bucket.
+ // execute the HTTP request.
response, err = client.Do(request)
c.Assert(err, IsNil)
verifyError(c, response, "InvalidArgument", "A specified event is not supported for notifications.", http.StatusBadRequest)
+
+ bucketNotificationDuplicates := `s3:ObjectCreated:Putprefiximages/1arn:minio:sns:us-east-1:444455556666:listens3:ObjectCreated:Putprefiximages/1arn:minio:sns:us-east-1:444455556666:listen`
+ request, err = newTestSignedRequest("PUT", getPutNotificationURL(s.endPoint, bucketName),
+ int64(len(bucketNotificationDuplicates)), bytes.NewReader([]byte(bucketNotificationDuplicates)), s.accessKey, s.secretKey)
+ c.Assert(err, IsNil)
+
+ client = http.Client{}
+ // execute the HTTP request.
+ response, err = client.Do(request)
+ c.Assert(err, IsNil)
+ verifyError(c, response, "InvalidArgument", "Configurations overlap. Configurations on the same bucket cannot share a common event type.", http.StatusBadRequest)
}
// TestBucketPolicy - Inserts the bucket policy and verifies it by fetching the policy back.
diff --git a/pkg/mimedb/db.go b/pkg/mimedb/db.go
index c73ee4f23..5a8b61743 100644
--- a/pkg/mimedb/db.go
+++ b/pkg/mimedb/db.go
@@ -1840,10 +1840,6 @@ var DB = map[string]struct {
ContentType: "image/vnd.ms-modi",
Compressible: false,
},
- "mdp": {
- ContentType: "application/dash+xml",
- Compressible: false,
- },
"me": {
ContentType: "text/troff",
Compressible: false,
@@ -2008,6 +2004,10 @@ var DB = map[string]struct {
ContentType: "application/vnd.mophun.certificate",
Compressible: false,
},
+ "mpd": {
+ ContentType: "application/dash+xml",
+ Compressible: false,
+ },
"mpe": {
ContentType: "video/mpeg",
Compressible: false,
@@ -2824,6 +2824,10 @@ var DB = map[string]struct {
ContentType: "application/relax-ng-compact-syntax",
Compressible: false,
},
+ "rng": {
+ ContentType: "application/xml",
+ Compressible: false,
+ },
"roa": {
ContentType: "application/rpki-roa",
Compressible: false,
@@ -3088,6 +3092,14 @@ var DB = map[string]struct {
ContentType: "application/vnd.openxmlformats-officedocument.presentationml.slide",
Compressible: false,
},
+ "slim": {
+ ContentType: "text/slim",
+ Compressible: false,
+ },
+ "slm": {
+ ContentType: "text/slim",
+ Compressible: false,
+ },
"slt": {
ContentType: "application/vnd.epson.salt",
Compressible: false,
diff --git a/pkg/mimedb/db_test.go b/pkg/mimedb/db_test.go
index f630bfdb3..7ef73b65c 100644
--- a/pkg/mimedb/db_test.go
+++ b/pkg/mimedb/db_test.go
@@ -1,5 +1,5 @@
/*
- * mime-db: Mime Database, (C) 2015 Minio, Inc.
+ * mime-db: Mime Database, (C) 2015, 2016 Minio, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,24 +14,18 @@
* limitations under the License.
*/
-package mimedb_test
+package mimedb
-import (
- "testing"
+import "testing"
- "github.com/minio/minio/pkg/mimedb"
-
- . "gopkg.in/check.v1"
-)
-
-func Test(t *testing.T) { TestingT(t) }
-
-type MySuite struct{}
-
-var _ = Suite(&MySuite{})
-
-func (s *MySuite) TestLookup(c *C) {
- // Test MustLookup.
- contentType := mimedb.DB["exe"].ContentType
- c.Assert(contentType, Not(Equals), "")
+func TestMimeLookup(t *testing.T) {
+ // Test mimeLookup.
+ contentType := DB["txt"].ContentType
+ if contentType != "text/plain" {
+ t.Fatalf("Invalid content type are found expected \"application/x-msdownload\", got %s", contentType)
+ }
+ compressible := DB["txt"].Compressible
+ if compressible != false {
+ t.Fatalf("Invalid content type are found expected \"false\", got %t", compressible)
+ }
}