Merge pull request #727 from harshavardhana/pr_out_all_other_api_s_now_support_signature_v4

All other API's now support signature v4
This commit is contained in:
Harshavardhana 2015-07-10 02:47:32 +00:00
commit eac92d4647
16 changed files with 652 additions and 491 deletions

View File

@ -87,6 +87,24 @@ type PartMetadata struct {
Size int64
}
// CompletePart - completed part container
type CompletePart struct {
PartNumber int
ETag string
}
// completedParts is a sortable interface for Part slice
type completedParts []CompletePart
func (a completedParts) Len() int { return len(a) }
func (a completedParts) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a completedParts) Less(i, j int) bool { return a[i].PartNumber < a[j].PartNumber }
// CompleteMultipartUpload container for completing multipart upload
type CompleteMultipartUpload struct {
Part []CompletePart
}
// ObjectResourcesMetadata - various types of object resources
type ObjectResourcesMetadata struct {
Bucket string

View File

@ -74,7 +74,7 @@ func (s *MyDonutSuite) SetUpSuite(c *C) {
c.Assert(err, IsNil)
// testing empty donut
buckets, err := dd.ListBuckets()
buckets, err := dd.ListBuckets(nil)
c.Assert(err, IsNil)
c.Assert(len(buckets), Equals, 0)
}
@ -86,20 +86,20 @@ func (s *MyDonutSuite) TearDownSuite(c *C) {
// test make bucket without name
func (s *MyDonutSuite) TestBucketWithoutNameFails(c *C) {
// fail to create new bucket without a name
err := dd.MakeBucket("", "private")
err := dd.MakeBucket("", "private", nil)
c.Assert(err, Not(IsNil))
err = dd.MakeBucket(" ", "private")
err = dd.MakeBucket(" ", "private", nil)
c.Assert(err, Not(IsNil))
}
// test empty bucket
func (s *MyDonutSuite) TestEmptyBucket(c *C) {
c.Assert(dd.MakeBucket("foo1", "private"), IsNil)
c.Assert(dd.MakeBucket("foo1", "private", nil), IsNil)
// check if bucket is empty
var resources BucketResourcesMetadata
resources.Maxkeys = 1
objectsMetadata, resources, err := dd.ListObjects("foo1", resources)
objectsMetadata, resources, err := dd.ListObjects("foo1", resources, nil)
c.Assert(err, IsNil)
c.Assert(len(objectsMetadata), Equals, 0)
c.Assert(resources.CommonPrefixes, DeepEquals, []string{})
@ -109,11 +109,11 @@ func (s *MyDonutSuite) TestEmptyBucket(c *C) {
// test bucket list
func (s *MyDonutSuite) TestMakeBucketAndList(c *C) {
// create bucket
err := dd.MakeBucket("foo2", "private")
err := dd.MakeBucket("foo2", "private", nil)
c.Assert(err, IsNil)
// check bucket exists
buckets, err := dd.ListBuckets()
buckets, err := dd.ListBuckets(nil)
c.Assert(err, IsNil)
c.Assert(len(buckets), Equals, 5)
c.Assert(buckets[0].ACL, Equals, BucketACL("private"))
@ -121,33 +121,33 @@ func (s *MyDonutSuite) TestMakeBucketAndList(c *C) {
// test re-create bucket
func (s *MyDonutSuite) TestMakeBucketWithSameNameFails(c *C) {
err := dd.MakeBucket("foo3", "private")
err := dd.MakeBucket("foo3", "private", nil)
c.Assert(err, IsNil)
err = dd.MakeBucket("foo3", "private")
err = dd.MakeBucket("foo3", "private", nil)
c.Assert(err, Not(IsNil))
}
// test make multiple buckets
func (s *MyDonutSuite) TestCreateMultipleBucketsAndList(c *C) {
// add a second bucket
err := dd.MakeBucket("foo4", "private")
err := dd.MakeBucket("foo4", "private", nil)
c.Assert(err, IsNil)
err = dd.MakeBucket("bar1", "private")
err = dd.MakeBucket("bar1", "private", nil)
c.Assert(err, IsNil)
buckets, err := dd.ListBuckets()
buckets, err := dd.ListBuckets(nil)
c.Assert(err, IsNil)
c.Assert(len(buckets), Equals, 2)
c.Assert(buckets[0].Name, Equals, "bar1")
c.Assert(buckets[1].Name, Equals, "foo4")
err = dd.MakeBucket("foobar1", "private")
err = dd.MakeBucket("foobar1", "private", nil)
c.Assert(err, IsNil)
buckets, err = dd.ListBuckets()
buckets, err = dd.ListBuckets(nil)
c.Assert(err, IsNil)
c.Assert(len(buckets), Equals, 3)
@ -156,7 +156,7 @@ func (s *MyDonutSuite) TestCreateMultipleBucketsAndList(c *C) {
// test object create without bucket
func (s *MyDonutSuite) TestNewObjectFailsWithoutBucket(c *C) {
_, err := dd.CreateObject("unknown", "obj", "", 0, nil, nil)
_, err := dd.CreateObject("unknown", "obj", "", 0, nil, nil, nil)
c.Assert(err, Not(IsNil))
}
@ -168,10 +168,10 @@ func (s *MyDonutSuite) TestNewObjectMetadata(c *C) {
expectedMd5Sum := base64.StdEncoding.EncodeToString(hasher.Sum(nil))
reader := ioutil.NopCloser(bytes.NewReader([]byte(data)))
err := dd.MakeBucket("foo6", "private")
err := dd.MakeBucket("foo6", "private", nil)
c.Assert(err, IsNil)
objectMetadata, err := dd.CreateObject("foo6", "obj", expectedMd5Sum, int64(len(data)), reader, map[string]string{"contentType": "application/json"})
objectMetadata, err := dd.CreateObject("foo6", "obj", expectedMd5Sum, int64(len(data)), reader, map[string]string{"contentType": "application/json"}, nil)
c.Assert(err, IsNil)
c.Assert(objectMetadata.MD5Sum, Equals, hex.EncodeToString(hasher.Sum(nil)))
c.Assert(objectMetadata.Metadata["contentType"], Equals, "application/json")
@ -179,13 +179,13 @@ func (s *MyDonutSuite) TestNewObjectMetadata(c *C) {
// test create object fails without name
func (s *MyDonutSuite) TestNewObjectFailsWithEmptyName(c *C) {
_, err := dd.CreateObject("foo", "", "", 0, nil, nil)
_, err := dd.CreateObject("foo", "", "", 0, nil, nil, nil)
c.Assert(err, Not(IsNil))
}
// test create object
func (s *MyDonutSuite) TestNewObjectCanBeWritten(c *C) {
err := dd.MakeBucket("foo", "private")
err := dd.MakeBucket("foo", "private", nil)
c.Assert(err, IsNil)
data := "Hello World"
@ -195,7 +195,7 @@ func (s *MyDonutSuite) TestNewObjectCanBeWritten(c *C) {
expectedMd5Sum := base64.StdEncoding.EncodeToString(hasher.Sum(nil))
reader := ioutil.NopCloser(bytes.NewReader([]byte(data)))
actualMetadata, err := dd.CreateObject("foo", "obj", expectedMd5Sum, int64(len(data)), reader, map[string]string{"contentType": "application/octet-stream"})
actualMetadata, err := dd.CreateObject("foo", "obj", expectedMd5Sum, int64(len(data)), reader, map[string]string{"contentType": "application/octet-stream"}, nil)
c.Assert(err, IsNil)
c.Assert(actualMetadata.MD5Sum, Equals, hex.EncodeToString(hasher.Sum(nil)))
@ -205,7 +205,7 @@ func (s *MyDonutSuite) TestNewObjectCanBeWritten(c *C) {
c.Assert(size, Equals, int64(len(data)))
c.Assert(buffer.Bytes(), DeepEquals, []byte(data))
actualMetadata, err = dd.GetObjectMetadata("foo", "obj")
actualMetadata, err = dd.GetObjectMetadata("foo", "obj", nil)
c.Assert(err, IsNil)
c.Assert(hex.EncodeToString(hasher.Sum(nil)), Equals, actualMetadata.MD5Sum)
c.Assert(int64(len(data)), Equals, actualMetadata.Size)
@ -213,15 +213,15 @@ func (s *MyDonutSuite) TestNewObjectCanBeWritten(c *C) {
// test list objects
func (s *MyDonutSuite) TestMultipleNewObjects(c *C) {
c.Assert(dd.MakeBucket("foo5", "private"), IsNil)
c.Assert(dd.MakeBucket("foo5", "private", nil), IsNil)
one := ioutil.NopCloser(bytes.NewReader([]byte("one")))
_, err := dd.CreateObject("foo5", "obj1", "", int64(len("one")), one, nil)
_, err := dd.CreateObject("foo5", "obj1", "", int64(len("one")), one, nil, nil)
c.Assert(err, IsNil)
two := ioutil.NopCloser(bytes.NewReader([]byte("two")))
_, err = dd.CreateObject("foo5", "obj2", "", int64(len("two")), two, nil)
_, err = dd.CreateObject("foo5", "obj2", "", int64(len("two")), two, nil, nil)
c.Assert(err, IsNil)
var buffer1 bytes.Buffer
@ -244,7 +244,7 @@ func (s *MyDonutSuite) TestMultipleNewObjects(c *C) {
resources.Prefix = "o"
resources.Delimiter = "1"
resources.Maxkeys = 10
objectsMetadata, resources, err := dd.ListObjects("foo5", resources)
objectsMetadata, resources, err := dd.ListObjects("foo5", resources, nil)
c.Assert(err, IsNil)
c.Assert(resources.IsTruncated, Equals, false)
c.Assert(resources.CommonPrefixes[0], Equals, "obj1")
@ -253,7 +253,7 @@ func (s *MyDonutSuite) TestMultipleNewObjects(c *C) {
resources.Prefix = ""
resources.Delimiter = "1"
resources.Maxkeys = 10
objectsMetadata, resources, err = dd.ListObjects("foo5", resources)
objectsMetadata, resources, err = dd.ListObjects("foo5", resources, nil)
c.Assert(err, IsNil)
c.Assert(objectsMetadata[0].Object, Equals, "obj2")
c.Assert(resources.IsTruncated, Equals, false)
@ -263,14 +263,14 @@ func (s *MyDonutSuite) TestMultipleNewObjects(c *C) {
resources.Prefix = "o"
resources.Delimiter = ""
resources.Maxkeys = 10
objectsMetadata, resources, err = dd.ListObjects("foo5", resources)
objectsMetadata, resources, err = dd.ListObjects("foo5", resources, nil)
c.Assert(err, IsNil)
c.Assert(resources.IsTruncated, Equals, false)
c.Assert(objectsMetadata[0].Object, Equals, "obj1")
c.Assert(objectsMetadata[1].Object, Equals, "obj2")
three := ioutil.NopCloser(bytes.NewReader([]byte("three")))
_, err = dd.CreateObject("foo5", "obj3", "", int64(len("three")), three, nil)
_, err = dd.CreateObject("foo5", "obj3", "", int64(len("three")), three, nil, nil)
c.Assert(err, IsNil)
var buffer bytes.Buffer
@ -283,7 +283,7 @@ func (s *MyDonutSuite) TestMultipleNewObjects(c *C) {
resources.Prefix = "o"
resources.Delimiter = ""
resources.Maxkeys = 2
objectsMetadata, resources, err = dd.ListObjects("foo5", resources)
objectsMetadata, resources, err = dd.ListObjects("foo5", resources, nil)
c.Assert(err, IsNil)
c.Assert(resources.IsTruncated, Equals, true)
c.Assert(len(objectsMetadata), Equals, 2)

View File

@ -25,7 +25,6 @@ import (
"io"
"io/ioutil"
"log"
"net/http"
"runtime/debug"
"sort"
"strconv"
@ -33,6 +32,7 @@ import (
"sync"
"time"
"github.com/minio/minio/pkg/crypto/sha256"
"github.com/minio/minio/pkg/donut/cache/data"
"github.com/minio/minio/pkg/donut/cache/metadata"
"github.com/minio/minio/pkg/iodine"
@ -55,7 +55,6 @@ type Config struct {
// API - local variables
type API struct {
config *Config
req *http.Request
lock *sync.Mutex
objects *data.Cache
multiPartObjects map[string]*data.Cache
@ -124,11 +123,6 @@ func New() (Interface, error) {
return a, nil
}
// SetRequest API for setting request header
func (donut API) SetRequest(req *http.Request) {
donut.req = req
}
// GetObject - GET object from cache buffer
func (donut API) GetObject(w io.Writer, bucket string, object string) (int64, error) {
donut.lock.Lock()
@ -186,6 +180,7 @@ func (donut API) GetPartialObject(w io.Writer, bucket, object string, start, len
"start": strconv.FormatInt(start, 10),
"length": strconv.FormatInt(length, 10),
}
if !IsValidBucket(bucket) {
return 0, iodine.New(BucketNameInvalid{Bucket: bucket}, errParams)
}
@ -232,10 +227,20 @@ func (donut API) GetPartialObject(w io.Writer, bucket, object string, start, len
}
// GetBucketMetadata -
func (donut API) GetBucketMetadata(bucket string) (BucketMetadata, error) {
func (donut API) GetBucketMetadata(bucket string, signature *Signature) (BucketMetadata, error) {
donut.lock.Lock()
defer donut.lock.Unlock()
if signature != nil {
ok, err := signature.DoesSignatureMatch("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855")
if err != nil {
return BucketMetadata{}, iodine.New(err, nil)
}
if !ok {
return BucketMetadata{}, iodine.New(SignatureDoesNotMatch{}, nil)
}
}
if !IsValidBucket(bucket) {
return BucketMetadata{}, iodine.New(BucketNameInvalid{Bucket: bucket}, nil)
}
@ -255,10 +260,20 @@ func (donut API) GetBucketMetadata(bucket string) (BucketMetadata, error) {
}
// SetBucketMetadata -
func (donut API) SetBucketMetadata(bucket string, metadata map[string]string) error {
func (donut API) SetBucketMetadata(bucket string, metadata map[string]string, signature *Signature) error {
donut.lock.Lock()
defer donut.lock.Unlock()
if signature != nil {
ok, err := signature.DoesSignatureMatch("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855")
if err != nil {
return iodine.New(err, nil)
}
if !ok {
return iodine.New(SignatureDoesNotMatch{}, nil)
}
}
if !IsValidBucket(bucket) {
return iodine.New(BucketNameInvalid{Bucket: bucket}, nil)
}
@ -296,12 +311,12 @@ func isMD5SumEqual(expectedMD5Sum, actualMD5Sum string) error {
}
// CreateObject - create an object
func (donut API) CreateObject(bucket, key, expectedMD5Sum string, size int64, data io.Reader, metadata map[string]string) (ObjectMetadata, error) {
func (donut API) CreateObject(bucket, key, expectedMD5Sum string, size int64, data io.Reader, metadata map[string]string, signature *Signature) (ObjectMetadata, error) {
donut.lock.Lock()
defer donut.lock.Unlock()
contentType := metadata["contentType"]
objectMetadata, err := donut.createObject(bucket, key, contentType, expectedMD5Sum, size, data)
objectMetadata, err := donut.createObject(bucket, key, contentType, expectedMD5Sum, size, data, signature)
// free
debug.FreeOSMemory()
@ -309,7 +324,7 @@ func (donut API) CreateObject(bucket, key, expectedMD5Sum string, size int64, da
}
// createObject - PUT object to cache buffer
func (donut API) createObject(bucket, key, contentType, expectedMD5Sum string, size int64, data io.Reader) (ObjectMetadata, error) {
func (donut API) createObject(bucket, key, contentType, expectedMD5Sum string, size int64, data io.Reader, signature *Signature) (ObjectMetadata, error) {
if len(donut.config.NodeDiskMap) == 0 {
if size > int64(donut.config.MaxSize) {
generic := GenericObjectError{Bucket: bucket, Object: key}
@ -369,6 +384,7 @@ func (donut API) createObject(bucket, key, contentType, expectedMD5Sum string, s
}
// calculate md5
hash := md5.New()
sha256hash := sha256.New()
var err error
var totalLength int64
@ -376,12 +392,8 @@ func (donut API) createObject(bucket, key, contentType, expectedMD5Sum string, s
var length int
byteBuffer := make([]byte, 1024*1024)
length, err = data.Read(byteBuffer)
// While hash.Write() wouldn't mind a Nil byteBuffer
// It is necessary for us to verify this and break
if length == 0 {
break
}
hash.Write(byteBuffer[0:length])
sha256hash.Write(byteBuffer[0:length])
ok := donut.objects.Append(objectKey, byteBuffer[0:length])
if !ok {
return ObjectMetadata{}, iodine.New(InternalError{}, nil)
@ -405,6 +417,15 @@ func (donut API) createObject(bucket, key, contentType, expectedMD5Sum string, s
return ObjectMetadata{}, iodine.New(BadDigest{}, nil)
}
}
if signature != nil {
ok, err := signature.DoesSignatureMatch(hex.EncodeToString(sha256hash.Sum(nil)))
if err != nil {
return ObjectMetadata{}, iodine.New(err, nil)
}
if !ok {
return ObjectMetadata{}, iodine.New(SignatureDoesNotMatch{}, nil)
}
}
m := make(map[string]string)
m["contentType"] = contentType
@ -424,10 +445,20 @@ func (donut API) createObject(bucket, key, contentType, expectedMD5Sum string, s
}
// MakeBucket - create bucket in cache
func (donut API) MakeBucket(bucketName, acl string) error {
func (donut API) MakeBucket(bucketName, acl string, signature *Signature) error {
donut.lock.Lock()
defer donut.lock.Unlock()
if signature != nil {
ok, err := signature.DoesSignatureMatch("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855")
if err != nil {
return iodine.New(err, nil)
}
if !ok {
return iodine.New(SignatureDoesNotMatch{}, nil)
}
}
if donut.storedBuckets.Stats().Items == totalBuckets {
return iodine.New(TooManyBuckets{Bucket: bucketName}, nil)
}
@ -463,10 +494,20 @@ func (donut API) MakeBucket(bucketName, acl string) error {
}
// ListObjects - list objects from cache
func (donut API) ListObjects(bucket string, resources BucketResourcesMetadata) ([]ObjectMetadata, BucketResourcesMetadata, error) {
func (donut API) ListObjects(bucket string, resources BucketResourcesMetadata, signature *Signature) ([]ObjectMetadata, BucketResourcesMetadata, error) {
donut.lock.Lock()
defer donut.lock.Unlock()
if signature != nil {
ok, err := signature.DoesSignatureMatch("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855")
if err != nil {
return nil, BucketResourcesMetadata{}, iodine.New(err, nil)
}
if !ok {
return nil, BucketResourcesMetadata{}, iodine.New(SignatureDoesNotMatch{}, nil)
}
}
if !IsValidBucket(bucket) {
return nil, BucketResourcesMetadata{IsTruncated: false}, iodine.New(BucketNameInvalid{Bucket: bucket}, nil)
}
@ -556,10 +597,20 @@ func (b byBucketName) Swap(i, j int) { b[i], b[j] = b[j], b[i] }
func (b byBucketName) Less(i, j int) bool { return b[i].Name < b[j].Name }
// ListBuckets - List buckets from cache
func (donut API) ListBuckets() ([]BucketMetadata, error) {
func (donut API) ListBuckets(signature *Signature) ([]BucketMetadata, error) {
donut.lock.Lock()
defer donut.lock.Unlock()
if signature != nil {
ok, err := signature.DoesSignatureMatch("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855")
if err != nil {
return nil, iodine.New(err, nil)
}
if !ok {
return nil, iodine.New(SignatureDoesNotMatch{}, nil)
}
}
var results []BucketMetadata
if len(donut.config.NodeDiskMap) > 0 {
buckets, err := donut.listBuckets()
@ -580,10 +631,20 @@ func (donut API) ListBuckets() ([]BucketMetadata, error) {
}
// GetObjectMetadata - get object metadata from cache
func (donut API) GetObjectMetadata(bucket, key string) (ObjectMetadata, error) {
func (donut API) GetObjectMetadata(bucket, key string, signature *Signature) (ObjectMetadata, error) {
donut.lock.Lock()
defer donut.lock.Unlock()
if signature != nil {
ok, err := signature.DoesSignatureMatch("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855")
if err != nil {
return ObjectMetadata{}, iodine.New(err, nil)
}
if !ok {
return ObjectMetadata{}, iodine.New(SignatureDoesNotMatch{}, nil)
}
}
// check if bucket exists
if !IsValidBucket(bucket) {
return ObjectMetadata{}, iodine.New(BucketNameInvalid{Bucket: bucket}, nil)

View File

@ -49,7 +49,7 @@ func (s *MyCacheSuite) SetUpSuite(c *C) {
c.Assert(err, IsNil)
// testing empty cache
buckets, err := dc.ListBuckets()
buckets, err := dc.ListBuckets(nil)
c.Assert(err, IsNil)
c.Assert(len(buckets), Equals, 0)
}
@ -61,20 +61,20 @@ func (s *MyCacheSuite) TearDownSuite(c *C) {
// test make bucket without name
func (s *MyCacheSuite) TestBucketWithoutNameFails(c *C) {
// fail to create new bucket without a name
err := dc.MakeBucket("", "private")
err := dc.MakeBucket("", "private", nil)
c.Assert(err, Not(IsNil))
err = dc.MakeBucket(" ", "private")
err = dc.MakeBucket(" ", "private", nil)
c.Assert(err, Not(IsNil))
}
// test empty bucket
func (s *MyCacheSuite) TestEmptyBucket(c *C) {
c.Assert(dc.MakeBucket("foo1", "private"), IsNil)
c.Assert(dc.MakeBucket("foo1", "private", nil), IsNil)
// check if bucket is empty
var resources BucketResourcesMetadata
resources.Maxkeys = 1
objectsMetadata, resources, err := dc.ListObjects("foo1", resources)
objectsMetadata, resources, err := dc.ListObjects("foo1", resources, nil)
c.Assert(err, IsNil)
c.Assert(len(objectsMetadata), Equals, 0)
c.Assert(resources.CommonPrefixes, DeepEquals, []string{})
@ -84,11 +84,11 @@ func (s *MyCacheSuite) TestEmptyBucket(c *C) {
// test bucket list
func (s *MyCacheSuite) TestMakeBucketAndList(c *C) {
// create bucket
err := dc.MakeBucket("foo2", "private")
err := dc.MakeBucket("foo2", "private", nil)
c.Assert(err, IsNil)
// check bucket exists
buckets, err := dc.ListBuckets()
buckets, err := dc.ListBuckets(nil)
c.Assert(err, IsNil)
c.Assert(len(buckets), Equals, 5)
c.Assert(buckets[0].ACL, Equals, BucketACL("private"))
@ -96,33 +96,33 @@ func (s *MyCacheSuite) TestMakeBucketAndList(c *C) {
// test re-create bucket
func (s *MyCacheSuite) TestMakeBucketWithSameNameFails(c *C) {
err := dc.MakeBucket("foo3", "private")
err := dc.MakeBucket("foo3", "private", nil)
c.Assert(err, IsNil)
err = dc.MakeBucket("foo3", "private")
err = dc.MakeBucket("foo3", "private", nil)
c.Assert(err, Not(IsNil))
}
// test make multiple buckets
func (s *MyCacheSuite) TestCreateMultipleBucketsAndList(c *C) {
// add a second bucket
err := dc.MakeBucket("foo4", "private")
err := dc.MakeBucket("foo4", "private", nil)
c.Assert(err, IsNil)
err = dc.MakeBucket("bar1", "private")
err = dc.MakeBucket("bar1", "private", nil)
c.Assert(err, IsNil)
buckets, err := dc.ListBuckets()
buckets, err := dc.ListBuckets(nil)
c.Assert(err, IsNil)
c.Assert(len(buckets), Equals, 2)
c.Assert(buckets[0].Name, Equals, "bar1")
c.Assert(buckets[1].Name, Equals, "foo4")
err = dc.MakeBucket("foobar1", "private")
err = dc.MakeBucket("foobar1", "private", nil)
c.Assert(err, IsNil)
buckets, err = dc.ListBuckets()
buckets, err = dc.ListBuckets(nil)
c.Assert(err, IsNil)
c.Assert(len(buckets), Equals, 3)
@ -131,7 +131,7 @@ func (s *MyCacheSuite) TestCreateMultipleBucketsAndList(c *C) {
// test object create without bucket
func (s *MyCacheSuite) TestNewObjectFailsWithoutBucket(c *C) {
_, err := dc.CreateObject("unknown", "obj", "", 0, nil, nil)
_, err := dc.CreateObject("unknown", "obj", "", 0, nil, nil, nil)
c.Assert(err, Not(IsNil))
}
@ -143,10 +143,10 @@ func (s *MyCacheSuite) TestNewObjectMetadata(c *C) {
expectedMd5Sum := base64.StdEncoding.EncodeToString(hasher.Sum(nil))
reader := ioutil.NopCloser(bytes.NewReader([]byte(data)))
err := dc.MakeBucket("foo6", "private")
err := dc.MakeBucket("foo6", "private", nil)
c.Assert(err, IsNil)
objectMetadata, err := dc.CreateObject("foo6", "obj", expectedMd5Sum, int64(len(data)), reader, map[string]string{"contentType": "application/json"})
objectMetadata, err := dc.CreateObject("foo6", "obj", expectedMd5Sum, int64(len(data)), reader, map[string]string{"contentType": "application/json"}, nil)
c.Assert(err, IsNil)
c.Assert(objectMetadata.MD5Sum, Equals, hex.EncodeToString(hasher.Sum(nil)))
c.Assert(objectMetadata.Metadata["contentType"], Equals, "application/json")
@ -154,13 +154,13 @@ func (s *MyCacheSuite) TestNewObjectMetadata(c *C) {
// test create object fails without name
func (s *MyCacheSuite) TestNewObjectFailsWithEmptyName(c *C) {
_, err := dc.CreateObject("foo", "", "", 0, nil, nil)
_, err := dc.CreateObject("foo", "", "", 0, nil, nil, nil)
c.Assert(err, Not(IsNil))
}
// test create object
func (s *MyCacheSuite) TestNewObjectCanBeWritten(c *C) {
err := dc.MakeBucket("foo", "private")
err := dc.MakeBucket("foo", "private", nil)
c.Assert(err, IsNil)
data := "Hello World"
@ -170,7 +170,7 @@ func (s *MyCacheSuite) TestNewObjectCanBeWritten(c *C) {
expectedMd5Sum := base64.StdEncoding.EncodeToString(hasher.Sum(nil))
reader := ioutil.NopCloser(bytes.NewReader([]byte(data)))
actualMetadata, err := dc.CreateObject("foo", "obj", expectedMd5Sum, int64(len(data)), reader, map[string]string{"contentType": "application/octet-stream"})
actualMetadata, err := dc.CreateObject("foo", "obj", expectedMd5Sum, int64(len(data)), reader, map[string]string{"contentType": "application/octet-stream"}, nil)
c.Assert(err, IsNil)
c.Assert(actualMetadata.MD5Sum, Equals, hex.EncodeToString(hasher.Sum(nil)))
@ -180,7 +180,7 @@ func (s *MyCacheSuite) TestNewObjectCanBeWritten(c *C) {
c.Assert(size, Equals, int64(len(data)))
c.Assert(buffer.Bytes(), DeepEquals, []byte(data))
actualMetadata, err = dc.GetObjectMetadata("foo", "obj")
actualMetadata, err = dc.GetObjectMetadata("foo", "obj", nil)
c.Assert(err, IsNil)
c.Assert(hex.EncodeToString(hasher.Sum(nil)), Equals, actualMetadata.MD5Sum)
c.Assert(int64(len(data)), Equals, actualMetadata.Size)
@ -188,15 +188,15 @@ func (s *MyCacheSuite) TestNewObjectCanBeWritten(c *C) {
// test list objects
func (s *MyCacheSuite) TestMultipleNewObjects(c *C) {
c.Assert(dc.MakeBucket("foo5", "private"), IsNil)
c.Assert(dc.MakeBucket("foo5", "private", nil), IsNil)
one := ioutil.NopCloser(bytes.NewReader([]byte("one")))
_, err := dc.CreateObject("foo5", "obj1", "", int64(len("one")), one, nil)
_, err := dc.CreateObject("foo5", "obj1", "", int64(len("one")), one, nil, nil)
c.Assert(err, IsNil)
two := ioutil.NopCloser(bytes.NewReader([]byte("two")))
_, err = dc.CreateObject("foo5", "obj2", "", int64(len("two")), two, nil)
_, err = dc.CreateObject("foo5", "obj2", "", int64(len("two")), two, nil, nil)
c.Assert(err, IsNil)
var buffer1 bytes.Buffer
@ -219,7 +219,7 @@ func (s *MyCacheSuite) TestMultipleNewObjects(c *C) {
resources.Prefix = "o"
resources.Delimiter = "1"
resources.Maxkeys = 10
objectsMetadata, resources, err := dc.ListObjects("foo5", resources)
objectsMetadata, resources, err := dc.ListObjects("foo5", resources, nil)
c.Assert(err, IsNil)
c.Assert(resources.IsTruncated, Equals, false)
c.Assert(resources.CommonPrefixes[0], Equals, "obj1")
@ -228,7 +228,7 @@ func (s *MyCacheSuite) TestMultipleNewObjects(c *C) {
resources.Prefix = ""
resources.Delimiter = "1"
resources.Maxkeys = 10
objectsMetadata, resources, err = dc.ListObjects("foo5", resources)
objectsMetadata, resources, err = dc.ListObjects("foo5", resources, nil)
c.Assert(err, IsNil)
c.Assert(objectsMetadata[0].Object, Equals, "obj2")
c.Assert(resources.IsTruncated, Equals, false)
@ -238,14 +238,14 @@ func (s *MyCacheSuite) TestMultipleNewObjects(c *C) {
resources.Prefix = "o"
resources.Delimiter = ""
resources.Maxkeys = 10
objectsMetadata, resources, err = dc.ListObjects("foo5", resources)
objectsMetadata, resources, err = dc.ListObjects("foo5", resources, nil)
c.Assert(err, IsNil)
c.Assert(resources.IsTruncated, Equals, false)
c.Assert(objectsMetadata[0].Object, Equals, "obj1")
c.Assert(objectsMetadata[1].Object, Equals, "obj2")
three := ioutil.NopCloser(bytes.NewReader([]byte("three")))
_, err = dc.CreateObject("foo5", "obj3", "", int64(len("three")), three, nil)
_, err = dc.CreateObject("foo5", "obj3", "", int64(len("three")), three, nil, nil)
c.Assert(err, IsNil)
var buffer bytes.Buffer
@ -258,7 +258,7 @@ func (s *MyCacheSuite) TestMultipleNewObjects(c *C) {
resources.Prefix = "o"
resources.Delimiter = ""
resources.Maxkeys = 2
objectsMetadata, resources, err = dc.ListObjects("foo5", resources)
objectsMetadata, resources, err = dc.ListObjects("foo5", resources, nil)
c.Assert(err, IsNil)
c.Assert(resources.IsTruncated, Equals, true)
c.Assert(len(objectsMetadata), Equals, 2)

View File

@ -334,3 +334,19 @@ type MissingDateHeader struct{}
func (e MissingDateHeader) Error() string {
return "Missing date header"
}
// InvalidPartOrder parts are not ordered as Requested
type InvalidPartOrder struct {
UploadID string
}
func (e InvalidPartOrder) Error() string {
return "Invalid part order sent for " + e.UploadID
}
// MalformedXML invalid xml format
type MalformedXML struct{}
func (e MalformedXML) Error() string {
return "Malformed XML"
}

View File

@ -29,31 +29,32 @@ type Interface interface {
// ObjectStorage is a donut object storage interface
type ObjectStorage interface {
// Storage service operations
GetBucketMetadata(bucket string) (BucketMetadata, error)
SetBucketMetadata(bucket string, metadata map[string]string) error
ListBuckets() ([]BucketMetadata, error)
MakeBucket(bucket string, ACL string) error
GetBucketMetadata(bucket string, signature *Signature) (BucketMetadata, error)
SetBucketMetadata(bucket string, metadata map[string]string, signature *Signature) error
ListBuckets(signature *Signature) ([]BucketMetadata, error)
MakeBucket(bucket string, ACL string, signature *Signature) error
// Bucket operations
ListObjects(bucket string, resources BucketResourcesMetadata) ([]ObjectMetadata, BucketResourcesMetadata, error)
ListObjects(string, BucketResourcesMetadata, *Signature) ([]ObjectMetadata, BucketResourcesMetadata, error)
// Object operations
GetObject(w io.Writer, bucket, object string) (int64, error)
GetPartialObject(w io.Writer, bucket, object string, start, length int64) (int64, error)
GetObjectMetadata(bucket, object string) (ObjectMetadata, error)
CreateObject(bucket, object, expectedMD5Sum string, size int64, reader io.Reader, metadata map[string]string) (ObjectMetadata, error)
GetObjectMetadata(bucket, object string, signature *Signature) (ObjectMetadata, error)
// bucket, object, expectedMD5Sum, size, reader, metadata, signature
CreateObject(string, string, string, int64, io.Reader, map[string]string, *Signature) (ObjectMetadata, error)
Multipart
}
// Multipart API
type Multipart interface {
NewMultipartUpload(bucket, key, contentType string) (string, error)
AbortMultipartUpload(bucket, key, uploadID string) error
CreateObjectPart(bucket, key, uploadID string, partID int, contentType, expectedMD5Sum string, size int64, data io.Reader) (string, error)
CompleteMultipartUpload(bucket, key, uploadID string, parts map[int]string) (ObjectMetadata, error)
ListMultipartUploads(bucket string, resources BucketMultipartResourcesMetadata) (BucketMultipartResourcesMetadata, error)
ListObjectParts(bucket, key string, resources ObjectResourcesMetadata) (ObjectResourcesMetadata, error)
NewMultipartUpload(bucket, key, contentType string, signature *Signature) (string, error)
AbortMultipartUpload(bucket, key, uploadID string, signature *Signature) error
CreateObjectPart(string, string, string, int, string, string, int64, io.Reader, *Signature) (string, error)
CompleteMultipartUpload(bucket, key, uploadID string, data io.Reader, signature *Signature) (ObjectMetadata, error)
ListMultipartUploads(string, BucketMultipartResourcesMetadata, *Signature) (BucketMultipartResourcesMetadata, error)
ListObjectParts(string, string, ObjectResourcesMetadata, *Signature) (ObjectResourcesMetadata, error)
}
// Management is a donut management system interface

View File

@ -22,8 +22,10 @@ import (
"crypto/sha512"
"encoding/base64"
"encoding/hex"
"encoding/xml"
"errors"
"io"
"io/ioutil"
"math/rand"
"runtime/debug"
"sort"
@ -31,15 +33,26 @@ import (
"strings"
"time"
"github.com/minio/minio/pkg/crypto/sha256"
"github.com/minio/minio/pkg/donut/cache/data"
"github.com/minio/minio/pkg/iodine"
)
// NewMultipartUpload - initiate a new multipart session
func (donut API) NewMultipartUpload(bucket, key, contentType string) (string, error) {
func (donut API) NewMultipartUpload(bucket, key, contentType string, signature *Signature) (string, error) {
donut.lock.Lock()
defer donut.lock.Unlock()
if signature != nil {
ok, err := signature.DoesSignatureMatch("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855")
if err != nil {
return "", iodine.New(err, nil)
}
if !ok {
return "", iodine.New(SignatureDoesNotMatch{}, nil)
}
}
if !IsValidBucket(bucket) {
return "", iodine.New(BucketNameInvalid{Bucket: bucket}, nil)
}
@ -71,10 +84,20 @@ func (donut API) NewMultipartUpload(bucket, key, contentType string) (string, er
}
// AbortMultipartUpload - abort an incomplete multipart session
func (donut API) AbortMultipartUpload(bucket, key, uploadID string) error {
func (donut API) AbortMultipartUpload(bucket, key, uploadID string, signature *Signature) error {
donut.lock.Lock()
defer donut.lock.Unlock()
if signature != nil {
ok, err := signature.DoesSignatureMatch("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855")
if err != nil {
return iodine.New(err, nil)
}
if !ok {
return iodine.New(SignatureDoesNotMatch{}, nil)
}
}
if !IsValidBucket(bucket) {
return iodine.New(BucketNameInvalid{Bucket: bucket}, nil)
}
@ -90,11 +113,11 @@ func (donut API) AbortMultipartUpload(bucket, key, uploadID string) error {
}
// CreateObjectPart - create a part in a multipart session
func (donut API) CreateObjectPart(bucket, key, uploadID string, partID int, contentType, expectedMD5Sum string, size int64, data io.Reader) (string, error) {
func (donut API) CreateObjectPart(bucket, key, uploadID string, partID int, contentType, expectedMD5Sum string, size int64, data io.Reader, signature *Signature) (string, error) {
donut.lock.Lock()
defer donut.lock.Unlock()
etag, err := donut.createObjectPart(bucket, key, uploadID, partID, "", expectedMD5Sum, size, data)
etag, err := donut.createObjectPart(bucket, key, uploadID, partID, "", expectedMD5Sum, size, data, signature)
// possible free
debug.FreeOSMemory()
@ -102,7 +125,7 @@ func (donut API) CreateObjectPart(bucket, key, uploadID string, partID int, cont
}
// createObject - internal wrapper function called by CreateObjectPart
func (donut API) createObjectPart(bucket, key, uploadID string, partID int, contentType, expectedMD5Sum string, size int64, data io.Reader) (string, error) {
func (donut API) createObjectPart(bucket, key, uploadID string, partID int, contentType, expectedMD5Sum string, size int64, data io.Reader, signature *Signature) (string, error) {
if !IsValidBucket(bucket) {
return "", iodine.New(BucketNameInvalid{Bucket: bucket}, nil)
}
@ -138,6 +161,7 @@ func (donut API) createObjectPart(bucket, key, uploadID string, partID int, cont
// calculate md5
hash := md5.New()
sha256hash := sha256.New()
var err error
var totalLength int64
@ -145,12 +169,8 @@ func (donut API) createObjectPart(bucket, key, uploadID string, partID int, cont
var length int
byteBuffer := make([]byte, 1024*1024)
length, err = data.Read(byteBuffer)
// While hash.Write() wouldn't mind a Nil byteBuffer
// It is necessary for us to verify this and break
if length == 0 {
break
}
hash.Write(byteBuffer[0:length])
sha256hash.Write(byteBuffer[0:length])
ok := donut.multiPartObjects[uploadID].Append(partID, byteBuffer[0:length])
if !ok {
return "", iodine.New(InternalError{}, nil)
@ -174,6 +194,17 @@ func (donut API) createObjectPart(bucket, key, uploadID string, partID int, cont
return "", iodine.New(BadDigest{}, nil)
}
}
if signature != nil {
ok, err := signature.DoesSignatureMatch(hex.EncodeToString(sha256hash.Sum(nil)))
if err != nil {
return "", iodine.New(err, nil)
}
if !ok {
return "", iodine.New(SignatureDoesNotMatch{}, nil)
}
}
newPart := PartMetadata{
PartNumber: partID,
LastModified: time.Now().UTC(),
@ -200,7 +231,7 @@ func (donut API) cleanupMultipartSession(bucket, key, uploadID string) {
}
// CompleteMultipartUpload - complete a multipart upload and persist the data
func (donut API) CompleteMultipartUpload(bucket, key, uploadID string, parts map[int]string) (ObjectMetadata, error) {
func (donut API) CompleteMultipartUpload(bucket, key, uploadID string, data io.Reader, signature *Signature) (ObjectMetadata, error) {
donut.lock.Lock()
if !IsValidBucket(bucket) {
@ -221,11 +252,36 @@ func (donut API) CompleteMultipartUpload(bucket, key, uploadID string, parts map
donut.lock.Unlock()
return ObjectMetadata{}, iodine.New(InvalidUploadID{UploadID: uploadID}, nil)
}
partBytes, err := ioutil.ReadAll(data)
if err != nil {
donut.lock.Unlock()
return ObjectMetadata{}, iodine.New(err, nil)
}
if signature != nil {
ok, err := signature.DoesSignatureMatch(hex.EncodeToString(sha256.Sum256(partBytes)[:]))
if err != nil {
donut.lock.Unlock()
return ObjectMetadata{}, iodine.New(err, nil)
}
if !ok {
donut.lock.Unlock()
return ObjectMetadata{}, iodine.New(SignatureDoesNotMatch{}, nil)
}
}
parts := &CompleteMultipartUpload{}
if err := xml.Unmarshal(partBytes, parts); err != nil {
donut.lock.Unlock()
return ObjectMetadata{}, iodine.New(MalformedXML{}, nil)
}
if !sort.IsSorted(completedParts(parts.Part)) {
donut.lock.Unlock()
return ObjectMetadata{}, iodine.New(InvalidPartOrder{}, nil)
}
var size int64
var fullObject bytes.Buffer
for i := 1; i <= len(parts); i++ {
recvMD5 := parts[i]
object, ok := donut.multiPartObjects[uploadID].Get(i)
for i := 1; i <= len(parts.Part); i++ {
recvMD5 := parts.Part[i-1].ETag
object, ok := donut.multiPartObjects[uploadID].Get(parts.Part[i-1].PartNumber)
if ok == false {
donut.lock.Unlock()
return ObjectMetadata{}, iodine.New(errors.New("missing part: "+strconv.Itoa(i)), nil)
@ -255,7 +311,7 @@ func (donut API) CompleteMultipartUpload(bucket, key, uploadID string, parts map
// this is needed for final verification inside CreateObject, do not convert this to hex
md5sum := base64.StdEncoding.EncodeToString(md5sumSlice[:])
donut.lock.Unlock()
objectMetadata, err := donut.CreateObject(bucket, key, md5sum, size, &fullObject, nil)
objectMetadata, err := donut.CreateObject(bucket, key, md5sum, size, &fullObject, nil, nil)
if err != nil {
// No need to call internal cleanup functions here, caller will call AbortMultipartUpload()
// which would in-turn cleanup properly in accordance with S3 Spec
@ -277,14 +333,25 @@ func (a byKey) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a byKey) Less(i, j int) bool { return a[i].Key < a[j].Key }
// ListMultipartUploads - list incomplete multipart sessions for a given bucket
func (donut API) ListMultipartUploads(bucket string, resources BucketMultipartResourcesMetadata) (BucketMultipartResourcesMetadata, error) {
func (donut API) ListMultipartUploads(bucket string, resources BucketMultipartResourcesMetadata, signature *Signature) (BucketMultipartResourcesMetadata, error) {
// TODO handle delimiter
donut.lock.Lock()
defer donut.lock.Unlock()
if signature != nil {
ok, err := signature.DoesSignatureMatch("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855")
if err != nil {
return BucketMultipartResourcesMetadata{}, iodine.New(err, nil)
}
if !ok {
return BucketMultipartResourcesMetadata{}, iodine.New(SignatureDoesNotMatch{}, nil)
}
}
if !donut.storedBuckets.Exists(bucket) {
return BucketMultipartResourcesMetadata{}, iodine.New(BucketNotFound{Bucket: bucket}, nil)
}
storedBucket := donut.storedBuckets.Get(bucket).(storedBucket)
var uploads []*UploadMetadata
@ -340,11 +407,21 @@ func (a partNumber) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a partNumber) Less(i, j int) bool { return a[i].PartNumber < a[j].PartNumber }
// ListObjectParts - list parts from incomplete multipart session for a given object
func (donut API) ListObjectParts(bucket, key string, resources ObjectResourcesMetadata) (ObjectResourcesMetadata, error) {
func (donut API) ListObjectParts(bucket, key string, resources ObjectResourcesMetadata, signature *Signature) (ObjectResourcesMetadata, error) {
// Verify upload id
donut.lock.Lock()
defer donut.lock.Unlock()
if signature != nil {
ok, err := signature.DoesSignatureMatch("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855")
if err != nil {
return ObjectResourcesMetadata{}, iodine.New(err, nil)
}
if !ok {
return ObjectResourcesMetadata{}, iodine.New(SignatureDoesNotMatch{}, nil)
}
}
if !donut.storedBuckets.Exists(bucket) {
return ObjectResourcesMetadata{}, iodine.New(BucketNotFound{Bucket: bucket}, nil)
}

View File

@ -21,7 +21,6 @@ import (
"crypto/hmac"
"encoding/hex"
"errors"
"io"
"net/http"
"regexp"
"sort"
@ -29,30 +28,30 @@ import (
"time"
"unicode/utf8"
"github.com/minio/minio/pkg/auth"
"github.com/minio/minio/pkg/crypto/sha256"
"github.com/minio/minio/pkg/iodine"
)
// request - a http request
type request struct {
receivedReq *http.Request
calculatedReq *http.Request
user *auth.User
body io.Reader
// Signature - local variables
type Signature struct {
AccessKeyID string
SecretAccessKey string
AuthHeader string
Request *http.Request
}
const (
authHeader = "AWS4-HMAC-SHA256"
iso8601Format = "20060102T150405Z"
yyyymmdd = "20060102"
authHeaderPrefix = "AWS4-HMAC-SHA256"
iso8601Format = "20060102T150405Z"
yyyymmdd = "20060102"
)
var ignoredHeaders = map[string]bool{
"Authorization": true,
"Content-Type": true,
"Content-Length": true,
"User-Agent": true,
"Authorization": true,
"Content-Type": true,
"Accept-Encoding": true,
"Content-Length": true,
"User-Agent": true,
}
// sumHMAC calculate hmac between two input byte array
@ -101,38 +100,11 @@ func urlEncodeName(name string) (string, error) {
return encodedName, nil
}
// newSignV4Request - populate a new signature v4 request
func newSignV4Request(user *auth.User, req *http.Request, body io.Reader) (*request, error) {
// save for subsequent use
r := new(request)
r.user = user
r.body = body
r.receivedReq = req
r.calculatedReq = req
return r, nil
}
// getHashedPayload get the hexadecimal value of the SHA256 hash of the request payload
func (r *request) getHashedPayload() string {
hash := func() string {
switch {
case r.body == nil:
return hex.EncodeToString(sha256.Sum256([]byte{}))
default:
sum256Bytes, _ := sha256.Sum(r.body)
return hex.EncodeToString(sum256Bytes)
}
}
hashedPayload := hash()
r.calculatedReq.Header.Set("x-amz-content-sha256", hashedPayload)
return hashedPayload
}
// getCanonicalHeaders generate a list of request headers with their values
func (r *request) getCanonicalHeaders() string {
func (r *Signature) getCanonicalHeaders() string {
var headers []string
vals := make(map[string][]string)
for k, vv := range r.calculatedReq.Header {
for k, vv := range r.Request.Header {
if _, ok := ignoredHeaders[http.CanonicalHeaderKey(k)]; ok {
continue // ignored header
}
@ -148,7 +120,7 @@ func (r *request) getCanonicalHeaders() string {
buf.WriteByte(':')
switch {
case k == "host":
buf.WriteString(r.calculatedReq.URL.Host)
buf.WriteString(r.Request.Host)
fallthrough
default:
for idx, v := range vals[k] {
@ -164,9 +136,9 @@ func (r *request) getCanonicalHeaders() string {
}
// getSignedHeaders generate a string i.e alphabetically sorted, semicolon-separated list of lowercase request header names
func (r *request) getSignedHeaders() string {
func (r *Signature) getSignedHeaders() string {
var headers []string
for k := range r.calculatedReq.Header {
for k := range r.Request.Header {
if _, ok := ignoredHeaders[http.CanonicalHeaderKey(k)]; ok {
continue // ignored header
}
@ -187,24 +159,24 @@ func (r *request) getSignedHeaders() string {
// <SignedHeaders>\n
// <HashedPayload>
//
func (r *request) getCanonicalRequest(hashedPayload string) string {
r.calculatedReq.URL.RawQuery = strings.Replace(r.calculatedReq.URL.Query().Encode(), "+", "%20", -1)
encodedPath, _ := urlEncodeName(r.calculatedReq.URL.Path)
func (r *Signature) getCanonicalRequest() string {
r.Request.URL.RawQuery = strings.Replace(r.Request.URL.Query().Encode(), "+", "%20", -1)
encodedPath, _ := urlEncodeName(r.Request.URL.Path)
// convert any space strings back to "+"
encodedPath = strings.Replace(encodedPath, "+", "%20", -1)
canonicalRequest := strings.Join([]string{
r.calculatedReq.Method,
r.Request.Method,
encodedPath,
r.calculatedReq.URL.RawQuery,
r.Request.URL.RawQuery,
r.getCanonicalHeaders(),
r.getSignedHeaders(),
hashedPayload,
r.Request.Header.Get("x-amz-content-sha256"),
}, "\n")
return canonicalRequest
}
// getScope generate a string of a specific date, an AWS region, and a service
func (r *request) getScope(t time.Time) string {
func (r *Signature) getScope(t time.Time) string {
scope := strings.Join([]string{
t.Format(yyyymmdd),
"milkyway",
@ -215,16 +187,16 @@ func (r *request) getScope(t time.Time) string {
}
// getStringToSign a string based on selected query values
func (r *request) getStringToSign(canonicalRequest string, t time.Time) string {
stringToSign := authHeader + "\n" + t.Format(iso8601Format) + "\n"
func (r *Signature) getStringToSign(canonicalRequest string, t time.Time) string {
stringToSign := authHeaderPrefix + "\n" + t.Format(iso8601Format) + "\n"
stringToSign = stringToSign + r.getScope(t) + "\n"
stringToSign = stringToSign + hex.EncodeToString(sha256.Sum256([]byte(canonicalRequest)))
return stringToSign
}
// getSigningKey hmac seed to calculate final signature
func (r *request) getSigningKey(t time.Time) []byte {
secret := r.user.SecretAccessKey
func (r *Signature) getSigningKey(t time.Time) []byte {
secret := r.SecretAccessKey
date := sumHMAC([]byte("AWS4"+secret), []byte(t.Format(yyyymmdd)))
region := sumHMAC(date, []byte("milkyway"))
service := sumHMAC(region, []byte("s3"))
@ -233,26 +205,29 @@ func (r *request) getSigningKey(t time.Time) []byte {
}
// getSignature final signature in hexadecimal form
func (r *request) getSignature(signingKey []byte, stringToSign string) string {
func (r *Signature) getSignature(signingKey []byte, stringToSign string) string {
return hex.EncodeToString(sumHMAC(signingKey, []byte(stringToSign)))
}
// SignV4 the request before Do(), in accordance with - http://docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-authenticating-requests.html
func (r *request) SignV4() (string, error) {
// DoesSignatureMatch - Verify authorization header with calculated header in accordance with - http://docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-authenticating-requests.html
// returns true if matches, false other wise if error is not nil then it is always false
func (r *Signature) DoesSignatureMatch(hashedPayload string) (bool, error) {
// set new calulated payload
r.Request.Header.Set("x-amz-content-sha256", hashedPayload)
// Add date if not present
var date string
if date = r.calculatedReq.Header.Get("x-amz-date"); date == "" {
if date = r.calculatedReq.Header.Get("Date"); date == "" {
return "", iodine.New(MissingDateHeader{}, nil)
if date = r.Request.Header.Get("x-amz-date"); date == "" {
if date = r.Request.Header.Get("Date"); date == "" {
return false, iodine.New(MissingDateHeader{}, nil)
}
}
t, err := time.Parse(iso8601Format, date)
if err != nil {
return "", iodine.New(err, nil)
return false, iodine.New(err, nil)
}
hashedPayload := r.getHashedPayload()
signedHeaders := r.getSignedHeaders()
canonicalRequest := r.getCanonicalRequest(hashedPayload)
canonicalRequest := r.getCanonicalRequest()
scope := r.getScope(t)
stringToSign := r.getStringToSign(canonicalRequest, t)
signingKey := r.getSigningKey(t)
@ -260,10 +235,13 @@ func (r *request) SignV4() (string, error) {
// final Authorization header
parts := []string{
authHeader + " Credential=" + r.user.AccessKeyID + "/" + scope,
authHeaderPrefix + " Credential=" + r.AccessKeyID + "/" + scope,
"SignedHeaders=" + signedHeaders,
"Signature=" + signature,
}
auth := strings.Join(parts, ", ")
return auth, nil
newAuthHeader := strings.Join(parts, ", ")
if newAuthHeader != r.AuthHeader {
return false, nil
}
return true, nil
}

View File

@ -29,7 +29,7 @@ func (api Minio) isValidOp(w http.ResponseWriter, req *http.Request, acceptsCont
vars := mux.Vars(req)
bucket := vars["bucket"]
bucketMetadata, err := api.Donut.GetBucketMetadata(bucket)
bucketMetadata, err := api.Donut.GetBucketMetadata(bucket, nil)
switch iodine.ToError(err).(type) {
case donut.BucketNotFound:
{
@ -42,7 +42,7 @@ func (api Minio) isValidOp(w http.ResponseWriter, req *http.Request, acceptsCont
return false
}
case nil:
if _, err := stripAuth(req); err != nil {
if _, err := StripAccessKeyID(req.Header.Get("Authorization")); err != nil {
if bucketMetadata.ACL.IsPrivate() {
return true
//uncomment this when we have webcli
@ -95,12 +95,23 @@ func (api Minio) ListMultipartUploadsHandler(w http.ResponseWriter, req *http.Re
vars := mux.Vars(req)
bucket := vars["bucket"]
resources, err := api.Donut.ListMultipartUploads(bucket, resources)
var signature *donut.Signature
if _, ok := req.Header["Authorization"]; ok {
// Init signature V4 verification
var err error
signature, err = InitSignatureV4(req)
if err != nil {
writeErrorResponse(w, req, InternalError, acceptsContentType, req.URL.Path)
return
}
}
resources, err := api.Donut.ListMultipartUploads(bucket, resources, signature)
switch iodine.ToError(err).(type) {
case nil: // success
{
// generate response
response := generateListMultipartUploadsResult(bucket, resources)
response := generateListMultipartUploadsResponse(bucket, resources)
encodedSuccessResponse := encodeSuccessResponse(response, acceptsContentType)
// write headers
setCommonHeaders(w, getContentTypeString(acceptsContentType), len(encodedSuccessResponse))
@ -153,7 +164,18 @@ func (api Minio) ListObjectsHandler(w http.ResponseWriter, req *http.Request) {
vars := mux.Vars(req)
bucket := vars["bucket"]
objects, resources, err := api.Donut.ListObjects(bucket, resources)
var signature *donut.Signature
if _, ok := req.Header["Authorization"]; ok {
// Init signature V4 verification
var err error
signature, err = InitSignatureV4(req)
if err != nil {
writeErrorResponse(w, req, InternalError, acceptsContentType, req.URL.Path)
return
}
}
objects, resources, err := api.Donut.ListObjects(bucket, resources, signature)
switch iodine.ToError(err).(type) {
case nil:
// generate response
@ -194,12 +216,23 @@ func (api Minio) ListBucketsHandler(w http.ResponseWriter, req *http.Request) {
acceptsContentType := getContentType(req)
// uncomment this when we have webcli
// without access key credentials one cannot list buckets
// if _, err := stripAuth(req); err != nil {
// if _, err := StripAccessKeyID(req); err != nil {
// writeErrorResponse(w, req, AccessDenied, acceptsContentType, req.URL.Path)
// return
// }
buckets, err := api.Donut.ListBuckets()
var signature *donut.Signature
if _, ok := req.Header["Authorization"]; ok {
// Init signature V4 verification
var err error
signature, err = InitSignatureV4(req)
if err != nil {
writeErrorResponse(w, req, InternalError, acceptsContentType, req.URL.Path)
return
}
}
buckets, err := api.Donut.ListBuckets(signature)
switch iodine.ToError(err).(type) {
case nil:
// generate response
@ -231,7 +264,7 @@ func (api Minio) PutBucketHandler(w http.ResponseWriter, req *http.Request) {
acceptsContentType := getContentType(req)
// uncomment this when we have webcli
// without access key credentials one cannot create a bucket
// if _, err := stripAuth(req); err != nil {
// if _, err := StripAccessKeyID(req); err != nil {
// writeErrorResponse(w, req, AccessDenied, acceptsContentType, req.URL.Path)
// return
// }
@ -250,7 +283,18 @@ func (api Minio) PutBucketHandler(w http.ResponseWriter, req *http.Request) {
vars := mux.Vars(req)
bucket := vars["bucket"]
err := api.Donut.MakeBucket(bucket, getACLTypeString(aclType))
var signature *donut.Signature
if _, ok := req.Header["Authorization"]; ok {
// Init signature V4 verification
var err error
signature, err = InitSignatureV4(req)
if err != nil {
writeErrorResponse(w, req, InternalError, acceptsContentType, req.URL.Path)
return
}
}
err := api.Donut.MakeBucket(bucket, getACLTypeString(aclType), signature)
switch iodine.ToError(err).(type) {
case nil:
// Make sure to add Location information here only for bucket
@ -293,7 +337,18 @@ func (api Minio) PutBucketACLHandler(w http.ResponseWriter, req *http.Request) {
vars := mux.Vars(req)
bucket := vars["bucket"]
err := api.Donut.SetBucketMetadata(bucket, map[string]string{"acl": getACLTypeString(aclType)})
var signature *donut.Signature
if _, ok := req.Header["Authorization"]; ok {
// Init signature V4 verification
var err error
signature, err = InitSignatureV4(req)
if err != nil {
writeErrorResponse(w, req, InternalError, acceptsContentType, req.URL.Path)
return
}
}
err := api.Donut.SetBucketMetadata(bucket, map[string]string{"acl": getACLTypeString(aclType)}, signature)
switch iodine.ToError(err).(type) {
case nil:
writeSuccessResponse(w, acceptsContentType)
@ -328,7 +383,18 @@ func (api Minio) HeadBucketHandler(w http.ResponseWriter, req *http.Request) {
vars := mux.Vars(req)
bucket := vars["bucket"]
_, err := api.Donut.GetBucketMetadata(bucket)
var signature *donut.Signature
if _, ok := req.Header["Authorization"]; ok {
// Init signature V4 verification
var err error
signature, err = InitSignatureV4(req)
if err != nil {
writeErrorResponse(w, req, InternalError, acceptsContentType, req.URL.Path)
return
}
}
_, err := api.Donut.GetBucketMetadata(bucket, signature)
switch iodine.ToError(err).(type) {
case nil:
writeSuccessResponse(w, acceptsContentType)

View File

@ -62,6 +62,14 @@ type ListObjectsResponse struct {
Prefix string
}
// Part container for part metadata
type Part struct {
PartNumber int
ETag string
LastModified string
Size int64
}
// ListPartsResponse - format for list parts response
type ListPartsResponse struct {
XMLName xml.Name `xml:"http://s3.amazonaws.com/doc/2006-03-01/ ListPartsResult" json:"-"`
@ -134,14 +142,6 @@ type Bucket struct {
CreationDate string
}
// Part container for part metadata
type Part struct {
PartNumber int
ETag string
LastModified string
Size int64
}
// Object container for object metadata
type Object struct {
ETag string
@ -164,8 +164,8 @@ type Owner struct {
DisplayName string
}
// InitiateMultipartUploadResult container for InitiateMultiPartUpload response, provides uploadID to start MultiPart upload
type InitiateMultipartUploadResult struct {
// InitiateMultipartUploadResponse container for InitiateMultiPartUpload response, provides uploadID to start MultiPart upload
type InitiateMultipartUploadResponse struct {
XMLName xml.Name `xml:"http://s3.amazonaws.com/doc/2006-03-01/ InitiateMultipartUploadResult" json:"-"`
Bucket string
@ -173,20 +173,8 @@ type InitiateMultipartUploadResult struct {
UploadID string `xml:"UploadId"`
}
// completedParts is a sortable interface for Part slice
type completedParts []Part
func (a completedParts) Len() int { return len(a) }
func (a completedParts) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a completedParts) Less(i, j int) bool { return a[i].PartNumber < a[j].PartNumber }
// CompleteMultipartUpload container for completing multipart upload
type CompleteMultipartUpload struct {
Part []Part
}
// CompleteMultipartUploadResult container for completed multipart upload response
type CompleteMultipartUploadResult struct {
// CompleteMultipartUploadResponse container for completed multipart upload response
type CompleteMultipartUploadResponse struct {
XMLName xml.Name `xml:"http://s3.amazonaws.com/doc/2006-03-01/ CompleteMultipartUploadResult" json:"-"`
Location string

View File

@ -19,7 +19,6 @@ package api
import (
"errors"
"net/http"
"strings"
"time"
"github.com/minio/minio/pkg/auth"
@ -41,64 +40,12 @@ type resourceHandler struct {
handler http.Handler
}
type authHeader struct {
prefix string
credential string
signedheaders string
signature string
accessKey string
}
const (
iso8601Format = "20060102T150405Z"
)
const (
authHeaderPrefix = "AWS4-HMAC-SHA256"
)
// strip auth from authorization header
func stripAuth(r *http.Request) (*authHeader, error) {
ah := r.Header.Get("Authorization")
if ah == "" {
return nil, errors.New("Missing auth header")
}
a := new(authHeader)
authFields := strings.Split(ah, ",")
if len(authFields) != 3 {
return nil, errors.New("Missing fields in Auth header")
}
authPrefixFields := strings.Fields(authFields[0])
if len(authPrefixFields) != 2 {
return nil, errors.New("Missing fields in Auth header")
}
if authPrefixFields[0] != authHeaderPrefix {
return nil, errors.New("Missing fields is Auth header")
}
credentials := strings.Split(authPrefixFields[1], "=")
if len(credentials) != 2 {
return nil, errors.New("Missing fields in Auth header")
}
signedheaders := strings.Split(authFields[1], "=")
if len(signedheaders) != 2 {
return nil, errors.New("Missing fields in Auth header")
}
signature := strings.Split(authFields[2], "=")
if len(signature) != 2 {
return nil, errors.New("Missing fields in Auth header")
}
a.credential = credentials[1]
a.signedheaders = signedheaders[1]
a.signature = signature[1]
a.accessKey = strings.Split(a.credential, "/")[0]
if !auth.IsValidAccessKey(a.accessKey) {
return nil, errors.New("Invalid access key")
}
return a, nil
}
func parseDate(req *http.Request) (time.Time, error) {
amzDate := req.Header.Get("X-Amz-Date")
amzDate := req.Header.Get("x-amz-date")
switch {
case amzDate != "":
if _, err := time.Parse(time.RFC1123, amzDate); err == nil {
@ -150,7 +97,7 @@ func (h timeHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
acceptsContentType := getContentType(r)
// Verify if date headers are set, if not reject the request
if r.Header.Get("Authorization") != "" {
if r.Header.Get("X-Amz-Date") == "" && r.Header.Get("Date") == "" {
if r.Header.Get("x-amz-date") == "" && r.Header.Get("Date") == "" {
// there is no way to knowing if this is a valid request, could be a attack reject such clients
writeErrorResponse(w, r, RequestTimeTooSkewed, acceptsContentType, r.URL.Path)
return
@ -181,20 +128,20 @@ func ValidateAuthHeaderHandler(h http.Handler) http.Handler {
// validate auth header handler ServeHTTP() wrapper
func (h validateAuthHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
acceptsContentType := getContentType(r)
ah, err := stripAuth(r)
accessKeyID, err := StripAccessKeyID(r.Header.Get("Authorization"))
switch err.(type) {
case nil:
// load auth config
authConfig, err := auth.LoadConfig()
if err != nil {
writeErrorResponse(w, r, InternalError, acceptsContentType, r.URL.Path)
return
}
_, ok := authConfig.Users[ah.accessKey]
if !ok {
writeErrorResponse(w, r, AccessDenied, acceptsContentType, r.URL.Path)
// Access key not found
if _, ok := authConfig.Users[accessKeyID]; !ok {
writeErrorResponse(w, r, InvalidAccessKeyID, acceptsContentType, r.URL.Path)
return
}
// Success
h.handler.ServeHTTP(w, r)
default:
// control reaches here, we should just send the request up the stack - internally

View File

@ -18,11 +18,8 @@ package api
import (
"net/http"
"sort"
"strconv"
"encoding/xml"
"github.com/gorilla/mux"
"github.com/minio/minio/pkg/donut"
"github.com/minio/minio/pkg/iodine"
@ -57,7 +54,18 @@ func (api Minio) GetObjectHandler(w http.ResponseWriter, req *http.Request) {
bucket = vars["bucket"]
object = vars["object"]
metadata, err := api.Donut.GetObjectMetadata(bucket, object)
var signature *donut.Signature
if _, ok := req.Header["Authorization"]; ok {
// Init signature V4 verification
var err error
signature, err = InitSignatureV4(req)
if err != nil {
writeErrorResponse(w, req, InternalError, acceptsContentType, req.URL.Path)
return
}
}
metadata, err := api.Donut.GetObjectMetadata(bucket, object, signature)
switch iodine.ToError(err).(type) {
case nil: // success
{
@ -120,7 +128,18 @@ func (api Minio) HeadObjectHandler(w http.ResponseWriter, req *http.Request) {
bucket = vars["bucket"]
object = vars["object"]
metadata, err := api.Donut.GetObjectMetadata(bucket, object)
var signature *donut.Signature
if _, ok := req.Header["Authorization"]; ok {
// Init signature V4 verification
var err error
signature, err = InitSignatureV4(req)
if err != nil {
writeErrorResponse(w, req, InternalError, acceptsContentType, req.URL.Path)
return
}
}
metadata, err := api.Donut.GetObjectMetadata(bucket, object, signature)
switch iodine.ToError(err).(type) {
case nil:
setObjectHeaders(w, metadata)
@ -205,7 +224,18 @@ func (api Minio) PutObjectHandler(w http.ResponseWriter, req *http.Request) {
return
}
metadata, err := api.Donut.CreateObject(bucket, object, md5, sizeInt64, req.Body, nil)
var signature *donut.Signature
if _, ok := req.Header["Authorization"]; ok {
// Init signature V4 verification
var err error
signature, err = InitSignatureV4(req)
if err != nil {
writeErrorResponse(w, req, InternalError, acceptsContentType, req.URL.Path)
return
}
}
metadata, err := api.Donut.CreateObject(bucket, object, md5, sizeInt64, req.Body, nil, signature)
switch iodine.ToError(err).(type) {
case nil:
w.Header().Set("ETag", metadata.MD5Sum)
@ -218,6 +248,10 @@ func (api Minio) PutObjectHandler(w http.ResponseWriter, req *http.Request) {
writeErrorResponse(w, req, MethodNotAllowed, acceptsContentType, req.URL.Path)
case donut.BadDigest:
writeErrorResponse(w, req, BadDigest, acceptsContentType, req.URL.Path)
case donut.MissingDateHeader:
writeErrorResponse(w, req, RequestTimeTooSkewed, acceptsContentType, req.URL.Path)
case donut.SignatureDoesNotMatch:
writeErrorResponse(w, req, SignatureDoesNotMatch, acceptsContentType, req.URL.Path)
case donut.IncompleteBody:
writeErrorResponse(w, req, IncompleteBody, acceptsContentType, req.URL.Path)
case donut.EntityTooLarge:
@ -258,11 +292,22 @@ func (api Minio) NewMultipartUploadHandler(w http.ResponseWriter, req *http.Requ
bucket = vars["bucket"]
object = vars["object"]
uploadID, err := api.Donut.NewMultipartUpload(bucket, object, "")
var signature *donut.Signature
if _, ok := req.Header["Authorization"]; ok {
// Init signature V4 verification
var err error
signature, err = InitSignatureV4(req)
if err != nil {
writeErrorResponse(w, req, InternalError, acceptsContentType, req.URL.Path)
return
}
}
uploadID, err := api.Donut.NewMultipartUpload(bucket, object, req.Header.Get("Content-Type"), signature)
switch iodine.ToError(err).(type) {
case nil:
{
response := generateInitiateMultipartUploadResult(bucket, object, uploadID)
response := generateInitiateMultipartUploadResponse(bucket, object, uploadID)
encodedSuccessResponse := encodeSuccessResponse(response, acceptsContentType)
// write headers
setCommonHeaders(w, getContentTypeString(acceptsContentType), len(encodedSuccessResponse))
@ -331,7 +376,18 @@ func (api Minio) PutObjectPartHandler(w http.ResponseWriter, req *http.Request)
writeErrorResponse(w, req, InvalidPart, acceptsContentType, req.URL.Path)
}
calculatedMD5, err := api.Donut.CreateObjectPart(bucket, object, uploadID, partID, "", md5, sizeInt64, req.Body)
var signature *donut.Signature
if _, ok := req.Header["Authorization"]; ok {
// Init signature V4 verification
var err error
signature, err = InitSignatureV4(req)
if err != nil {
writeErrorResponse(w, req, InternalError, acceptsContentType, req.URL.Path)
return
}
}
calculatedMD5, err := api.Donut.CreateObjectPart(bucket, object, uploadID, partID, "", md5, sizeInt64, req.Body, signature)
switch iodine.ToError(err).(type) {
case nil:
w.Header().Set("ETag", calculatedMD5)
@ -342,6 +398,8 @@ func (api Minio) PutObjectPartHandler(w http.ResponseWriter, req *http.Request)
writeErrorResponse(w, req, MethodNotAllowed, acceptsContentType, req.URL.Path)
case donut.BadDigest:
writeErrorResponse(w, req, BadDigest, acceptsContentType, req.URL.Path)
case donut.SignatureDoesNotMatch:
writeErrorResponse(w, req, SignatureDoesNotMatch, acceptsContentType, req.URL.Path)
case donut.IncompleteBody:
writeErrorResponse(w, req, IncompleteBody, acceptsContentType, req.URL.Path)
case donut.EntityTooLarge:
@ -376,7 +434,18 @@ func (api Minio) AbortMultipartUploadHandler(w http.ResponseWriter, req *http.Re
objectResourcesMetadata := getObjectResources(req.URL.Query())
err := api.Donut.AbortMultipartUpload(bucket, object, objectResourcesMetadata.UploadID)
var signature *donut.Signature
if _, ok := req.Header["Authorization"]; ok {
// Init signature V4 verification
var err error
signature, err = InitSignatureV4(req)
if err != nil {
writeErrorResponse(w, req, InternalError, acceptsContentType, req.URL.Path)
return
}
}
err := api.Donut.AbortMultipartUpload(bucket, object, objectResourcesMetadata.UploadID, signature)
switch iodine.ToError(err).(type) {
case nil:
setCommonHeaders(w, getContentTypeString(acceptsContentType), 0)
@ -414,11 +483,22 @@ func (api Minio) ListObjectPartsHandler(w http.ResponseWriter, req *http.Request
bucket := vars["bucket"]
object := vars["object"]
objectResourcesMetadata, err := api.Donut.ListObjectParts(bucket, object, objectResourcesMetadata)
var signature *donut.Signature
if _, ok := req.Header["Authorization"]; ok {
// Init signature V4 verification
var err error
signature, err = InitSignatureV4(req)
if err != nil {
writeErrorResponse(w, req, InternalError, acceptsContentType, req.URL.Path)
return
}
}
objectResourcesMetadata, err := api.Donut.ListObjectParts(bucket, object, objectResourcesMetadata, signature)
switch iodine.ToError(err).(type) {
case nil:
{
response := generateListPartsResult(objectResourcesMetadata)
response := generateListPartsResponse(objectResourcesMetadata)
encodedSuccessResponse := encodeSuccessResponse(response, acceptsContentType)
// write headers
setCommonHeaders(w, getContentTypeString(acceptsContentType), len(encodedSuccessResponse))
@ -449,35 +529,27 @@ func (api Minio) CompleteMultipartUploadHandler(w http.ResponseWriter, req *http
return
}
decoder := xml.NewDecoder(req.Body)
parts := &CompleteMultipartUpload{}
err := decoder.Decode(parts)
if err != nil {
log.Error.Println(iodine.New(err, nil))
writeErrorResponse(w, req, InternalError, acceptsContentType, req.URL.Path)
return
}
if !sort.IsSorted(completedParts(parts.Part)) {
writeErrorResponse(w, req, InvalidPartOrder, acceptsContentType, req.URL.Path)
return
}
vars := mux.Vars(req)
bucket := vars["bucket"]
object := vars["object"]
objectResourcesMetadata := getObjectResources(req.URL.Query())
partMap := make(map[int]string)
for _, part := range parts.Part {
partMap[part.PartNumber] = part.ETag
var signature *donut.Signature
if _, ok := req.Header["Authorization"]; ok {
// Init signature V4 verification
var err error
signature, err = InitSignatureV4(req)
if err != nil {
writeErrorResponse(w, req, InternalError, acceptsContentType, req.URL.Path)
return
}
}
metadata, err := api.Donut.CompleteMultipartUpload(bucket, object, objectResourcesMetadata.UploadID, partMap)
metadata, err := api.Donut.CompleteMultipartUpload(bucket, object, objectResourcesMetadata.UploadID, req.Body, signature)
switch iodine.ToError(err).(type) {
case nil:
{
response := generateCompleteMultpartUploadResult(bucket, object, "", metadata.MD5Sum)
response := generateCompleteMultpartUploadResponse(bucket, object, "", metadata.MD5Sum)
encodedSuccessResponse := encodeSuccessResponse(response, acceptsContentType)
// write headers
setCommonHeaders(w, getContentTypeString(acceptsContentType), len(encodedSuccessResponse))
@ -486,6 +558,16 @@ func (api Minio) CompleteMultipartUploadHandler(w http.ResponseWriter, req *http
}
case donut.InvalidUploadID:
writeErrorResponse(w, req, NoSuchUpload, acceptsContentType, req.URL.Path)
case donut.InvalidPartOrder:
writeErrorResponse(w, req, InvalidPartOrder, acceptsContentType, req.URL.Path)
case donut.MissingDateHeader:
writeErrorResponse(w, req, RequestTimeTooSkewed, acceptsContentType, req.URL.Path)
case donut.SignatureDoesNotMatch:
writeErrorResponse(w, req, SignatureDoesNotMatch, acceptsContentType, req.URL.Path)
case donut.IncompleteBody:
writeErrorResponse(w, req, IncompleteBody, acceptsContentType, req.URL.Path)
case donut.MalformedXML:
writeErrorResponse(w, req, MalformedXML, acceptsContentType, req.URL.Path)
default:
log.Error.Println(iodine.New(err, nil))
writeErrorResponse(w, req, InternalError, acceptsContentType, req.URL.Path)

View File

@ -85,7 +85,7 @@ func generateListObjectsResponse(bucket string, objects []donut.ObjectMetadata,
continue
}
content.Key = object.Object
content.LastModified = object.Created.Format(iso8601Format)
content.LastModified = object.Created.Format(rfcFormat)
content.ETag = "\"" + object.MD5Sum + "\""
content.Size = object.Size
content.StorageClass = "STANDARD"
@ -111,18 +111,18 @@ func generateListObjectsResponse(bucket string, objects []donut.ObjectMetadata,
return data
}
// generateInitiateMultipartUploadResult
func generateInitiateMultipartUploadResult(bucket, key, uploadID string) InitiateMultipartUploadResult {
return InitiateMultipartUploadResult{
// generateInitiateMultipartUploadResponse
func generateInitiateMultipartUploadResponse(bucket, key, uploadID string) InitiateMultipartUploadResponse {
return InitiateMultipartUploadResponse{
Bucket: bucket,
Key: key,
UploadID: uploadID,
}
}
// generateCompleteMultipartUploadResult
func generateCompleteMultpartUploadResult(bucket, key, location, etag string) CompleteMultipartUploadResult {
return CompleteMultipartUploadResult{
// generateCompleteMultipartUploadResponse
func generateCompleteMultpartUploadResponse(bucket, key, location, etag string) CompleteMultipartUploadResponse {
return CompleteMultipartUploadResponse{
Location: location,
Bucket: bucket,
Key: key,
@ -131,7 +131,7 @@ func generateCompleteMultpartUploadResult(bucket, key, location, etag string) Co
}
// generateListPartsResult
func generateListPartsResult(objectMetadata donut.ObjectResourcesMetadata) ListPartsResponse {
func generateListPartsResponse(objectMetadata donut.ObjectResourcesMetadata) ListPartsResponse {
// TODO - support EncodingType in xml decoding
listPartsResponse := ListPartsResponse{}
listPartsResponse.Bucket = objectMetadata.Bucket
@ -160,8 +160,8 @@ func generateListPartsResult(objectMetadata donut.ObjectResourcesMetadata) ListP
return listPartsResponse
}
// generateListMultipartUploadsResult
func generateListMultipartUploadsResult(bucket string, metadata donut.BucketMultipartResourcesMetadata) ListMultipartUploadsResponse {
// generateListMultipartUploadsResponse
func generateListMultipartUploadsResponse(bucket string, metadata donut.BucketMultipartResourcesMetadata) ListMultipartUploadsResponse {
listMultipartUploadsResponse := ListMultipartUploadsResponse{}
listMultipartUploadsResponse.Bucket = bucket
listMultipartUploadsResponse.Delimiter = metadata.Delimiter

View File

@ -0,0 +1,85 @@
/*
* Minimalist Object Storage, (C) 2015 Minio, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package api
import (
"errors"
"net/http"
"strings"
"github.com/minio/minio/pkg/auth"
"github.com/minio/minio/pkg/donut"
"github.com/minio/minio/pkg/iodine"
)
const (
authHeaderPrefix = "AWS4-HMAC-SHA256"
)
// StripAccessKeyID - strip only access key id from auth header
func StripAccessKeyID(ah string) (string, error) {
if ah == "" {
return "", errors.New("Missing auth header")
}
authFields := strings.Split(ah, ",")
if len(authFields) != 3 {
return "", errors.New("Missing fields in Auth header")
}
authPrefixFields := strings.Fields(authFields[0])
if len(authPrefixFields) != 2 {
return "", errors.New("Missing fields in Auth header")
}
if authPrefixFields[0] != authHeaderPrefix {
return "", errors.New("Missing fields is Auth header")
}
credentials := strings.Split(authPrefixFields[1], "=")
if len(credentials) != 2 {
return "", errors.New("Missing fields in Auth header")
}
if len(strings.Split(authFields[1], "=")) != 2 {
return "", errors.New("Missing fields in Auth header")
}
if len(strings.Split(authFields[2], "=")) != 2 {
return "", errors.New("Missing fields in Auth header")
}
accessKeyID := strings.Split(credentials[1], "/")[0]
if !auth.IsValidAccessKey(accessKeyID) {
return "", errors.New("Invalid access key")
}
return accessKeyID, nil
}
// InitSignatureV4 initializing signature verification
func InitSignatureV4(req *http.Request) (*donut.Signature, error) {
// strip auth from authorization header
ah := req.Header.Get("Authorization")
accessKeyID, err := StripAccessKeyID(ah)
if err != nil {
return nil, iodine.New(err, nil)
}
authConfig, err := auth.LoadConfig()
if _, ok := authConfig.Users[accessKeyID]; !ok {
return nil, errors.New("Access ID not found")
}
signature := &donut.Signature{
AccessKeyID: authConfig.Users[accessKeyID].AccessKeyID,
SecretAccessKey: authConfig.Users[accessKeyID].SecretAccessKey,
AuthHeader: ah,
Request: req,
}
return signature, nil
}

View File

@ -21,13 +21,13 @@ import (
"io/ioutil"
"strings"
"testing"
"time"
"encoding/xml"
"net/http"
"net/http/httptest"
. "github.com/minio/check"
"github.com/minio/minio/pkg/donut"
"github.com/minio/minio/pkg/server/api"
)
@ -49,16 +49,9 @@ func (s *MyAPIDonutCacheSuite) TearDownSuite(c *C) {
testAPIDonutCacheServer.Close()
}
func setDummyAuthHeader(req *http.Request) {
authDummy := "AWS4-HMAC-SHA256 Credential=AC5NH40NQLTL4DUMMY/20130524/us-east-1/s3/aws4_request, SignedHeaders=date;host;x-amz-content-sha256;x-amz-date;x-amz-storage-class, Signature=98ad721746da40c64f1a55b78f14c238d841ea1380cd77a1b5971af0ece108bd"
req.Header.Set("Authorization", authDummy)
req.Header.Set("Date", time.Now().UTC().Format(http.TimeFormat))
}
func (s *MyAPIDonutCacheSuite) TestNonExistantBucket(c *C) {
request, err := http.NewRequest("HEAD", testAPIDonutCacheServer.URL+"/nonexistantbucket", nil)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client := http.Client{}
response, err := client.Do(request)
@ -69,7 +62,6 @@ func (s *MyAPIDonutCacheSuite) TestNonExistantBucket(c *C) {
func (s *MyAPIDonutCacheSuite) TestEmptyObject(c *C) {
request, err := http.NewRequest("PUT", testAPIDonutCacheServer.URL+"/emptyobject", nil)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client := http.Client{}
response, err := client.Do(request)
@ -78,7 +70,6 @@ func (s *MyAPIDonutCacheSuite) TestEmptyObject(c *C) {
request, err = http.NewRequest("PUT", testAPIDonutCacheServer.URL+"/emptyobject/object", nil)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client = http.Client{}
response, err = client.Do(request)
@ -87,7 +78,6 @@ func (s *MyAPIDonutCacheSuite) TestEmptyObject(c *C) {
request, err = http.NewRequest("GET", testAPIDonutCacheServer.URL+"/emptyobject/object", nil)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client = http.Client{}
response, err = client.Do(request)
@ -103,7 +93,6 @@ func (s *MyAPIDonutCacheSuite) TestEmptyObject(c *C) {
func (s *MyAPIDonutCacheSuite) TestBucket(c *C) {
request, err := http.NewRequest("PUT", testAPIDonutCacheServer.URL+"/bucket", nil)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client := http.Client{}
response, err := client.Do(request)
@ -112,7 +101,6 @@ func (s *MyAPIDonutCacheSuite) TestBucket(c *C) {
request, err = http.NewRequest("HEAD", testAPIDonutCacheServer.URL+"/bucket", nil)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client = http.Client{}
response, err = client.Do(request)
@ -124,7 +112,6 @@ func (s *MyAPIDonutCacheSuite) TestObject(c *C) {
buffer := bytes.NewBufferString("hello world")
request, err := http.NewRequest("PUT", testAPIDonutCacheServer.URL+"/testobject", nil)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client := http.Client{}
response, err := client.Do(request)
@ -133,7 +120,6 @@ func (s *MyAPIDonutCacheSuite) TestObject(c *C) {
request, err = http.NewRequest("PUT", testAPIDonutCacheServer.URL+"/testobject/object", buffer)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client = http.Client{}
response, err = client.Do(request)
@ -142,7 +128,6 @@ func (s *MyAPIDonutCacheSuite) TestObject(c *C) {
request, err = http.NewRequest("GET", testAPIDonutCacheServer.URL+"/testobject/object", nil)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client = http.Client{}
response, err = client.Do(request)
@ -158,7 +143,6 @@ func (s *MyAPIDonutCacheSuite) TestObject(c *C) {
func (s *MyAPIDonutCacheSuite) TestMultipleObjects(c *C) {
request, err := http.NewRequest("PUT", testAPIDonutCacheServer.URL+"/multipleobjects", nil)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client := http.Client{}
response, err := client.Do(request)
@ -167,7 +151,6 @@ func (s *MyAPIDonutCacheSuite) TestMultipleObjects(c *C) {
request, err = http.NewRequest("GET", testAPIDonutCacheServer.URL+"/multipleobjects/object", nil)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client = http.Client{}
response, err = client.Do(request)
@ -180,7 +163,6 @@ func (s *MyAPIDonutCacheSuite) TestMultipleObjects(c *C) {
buffer1 := bytes.NewBufferString("hello one")
request, err = http.NewRequest("PUT", testAPIDonutCacheServer.URL+"/multipleobjects/object1", buffer1)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client = http.Client{}
response, err = client.Do(request)
@ -189,7 +171,6 @@ func (s *MyAPIDonutCacheSuite) TestMultipleObjects(c *C) {
request, err = http.NewRequest("GET", testAPIDonutCacheServer.URL+"/multipleobjects/object1", nil)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client = http.Client{}
response, err = client.Do(request)
@ -204,7 +185,6 @@ func (s *MyAPIDonutCacheSuite) TestMultipleObjects(c *C) {
buffer2 := bytes.NewBufferString("hello two")
request, err = http.NewRequest("PUT", testAPIDonutCacheServer.URL+"/multipleobjects/object2", buffer2)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client = http.Client{}
response, err = client.Do(request)
@ -213,7 +193,6 @@ func (s *MyAPIDonutCacheSuite) TestMultipleObjects(c *C) {
request, err = http.NewRequest("GET", testAPIDonutCacheServer.URL+"/multipleobjects/object2", nil)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client = http.Client{}
response, err = client.Do(request)
@ -228,7 +207,6 @@ func (s *MyAPIDonutCacheSuite) TestMultipleObjects(c *C) {
buffer3 := bytes.NewBufferString("hello three")
request, err = http.NewRequest("PUT", testAPIDonutCacheServer.URL+"/multipleobjects/object3", buffer3)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client = http.Client{}
response, err = client.Do(request)
@ -237,7 +215,6 @@ func (s *MyAPIDonutCacheSuite) TestMultipleObjects(c *C) {
request, err = http.NewRequest("GET", testAPIDonutCacheServer.URL+"/multipleobjects/object3", nil)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client = http.Client{}
response, err = client.Do(request)
@ -253,7 +230,6 @@ func (s *MyAPIDonutCacheSuite) TestMultipleObjects(c *C) {
func (s *MyAPIDonutCacheSuite) TestNotImplemented(c *C) {
request, err := http.NewRequest("GET", testAPIDonutCacheServer.URL+"/bucket/object?policy", nil)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client := http.Client{}
response, err := client.Do(request)
@ -265,7 +241,6 @@ func (s *MyAPIDonutCacheSuite) TestNotImplemented(c *C) {
func (s *MyAPIDonutCacheSuite) TestHeader(c *C) {
request, err := http.NewRequest("GET", testAPIDonutCacheServer.URL+"/bucket/object", nil)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client := http.Client{}
response, err := client.Do(request)
@ -278,7 +253,6 @@ func (s *MyAPIDonutCacheSuite) TestPutBucket(c *C) {
request, err := http.NewRequest("PUT", testAPIDonutCacheServer.URL+"/put-bucket", nil)
c.Assert(err, IsNil)
request.Header.Add("x-amz-acl", "private")
setDummyAuthHeader(request)
client := http.Client{}
response, err := client.Do(request)
@ -290,7 +264,6 @@ func (s *MyAPIDonutCacheSuite) TestPutObject(c *C) {
request, err := http.NewRequest("PUT", testAPIDonutCacheServer.URL+"/put-object", nil)
c.Assert(err, IsNil)
request.Header.Add("x-amz-acl", "private")
setDummyAuthHeader(request)
client := http.Client{}
response, err := client.Do(request)
@ -299,7 +272,6 @@ func (s *MyAPIDonutCacheSuite) TestPutObject(c *C) {
request, err = http.NewRequest("PUT", testAPIDonutCacheServer.URL+"/put-object/object", bytes.NewBufferString("hello world"))
c.Assert(err, IsNil)
setDummyAuthHeader(request)
response, err = client.Do(request)
c.Assert(err, IsNil)
@ -309,7 +281,6 @@ func (s *MyAPIDonutCacheSuite) TestPutObject(c *C) {
func (s *MyAPIDonutCacheSuite) TestListBuckets(c *C) {
request, err := http.NewRequest("GET", testAPIDonutCacheServer.URL+"/", nil)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client := http.Client{}
response, err := client.Do(request)
@ -325,7 +296,6 @@ func (s *MyAPIDonutCacheSuite) TestListBuckets(c *C) {
func (s *MyAPIDonutCacheSuite) TestNotBeAbleToCreateObjectInNonexistantBucket(c *C) {
request, err := http.NewRequest("PUT", testAPIDonutCacheServer.URL+"/innonexistantbucket/object", bytes.NewBufferString("hello world"))
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client := http.Client{}
response, err := client.Do(request)
@ -337,7 +307,6 @@ func (s *MyAPIDonutCacheSuite) TestHeadOnObject(c *C) {
request, err := http.NewRequest("PUT", testAPIDonutCacheServer.URL+"/headonobject", nil)
c.Assert(err, IsNil)
request.Header.Add("x-amz-acl", "private")
setDummyAuthHeader(request)
client := http.Client{}
response, err := client.Do(request)
@ -346,7 +315,6 @@ func (s *MyAPIDonutCacheSuite) TestHeadOnObject(c *C) {
request, err = http.NewRequest("PUT", testAPIDonutCacheServer.URL+"/headonobject/object1", bytes.NewBufferString("hello world"))
c.Assert(err, IsNil)
setDummyAuthHeader(request)
response, err = client.Do(request)
c.Assert(err, IsNil)
@ -354,7 +322,6 @@ func (s *MyAPIDonutCacheSuite) TestHeadOnObject(c *C) {
request, err = http.NewRequest("HEAD", testAPIDonutCacheServer.URL+"/headonobject/object1", nil)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
response, err = client.Do(request)
c.Assert(err, IsNil)
@ -365,7 +332,6 @@ func (s *MyAPIDonutCacheSuite) TestHeadOnBucket(c *C) {
request, err := http.NewRequest("PUT", testAPIDonutCacheServer.URL+"/headonbucket", nil)
c.Assert(err, IsNil)
request.Header.Add("x-amz-acl", "private")
setDummyAuthHeader(request)
client := http.Client{}
response, err := client.Do(request)
@ -374,18 +340,17 @@ func (s *MyAPIDonutCacheSuite) TestHeadOnBucket(c *C) {
request, err = http.NewRequest("HEAD", testAPIDonutCacheServer.URL+"/headonbucket", nil)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
response, err = client.Do(request)
c.Assert(err, IsNil)
c.Assert(response.StatusCode, Equals, http.StatusOK)
}
/* Enable when we have full working signature v4
func (s *MyAPIDonutCacheSuite) TestDateFormat(c *C) {
request, err := http.NewRequest("PUT", testAPIDonutCacheServer.URL+"/dateformat", nil)
c.Assert(err, IsNil)
request.Header.Add("x-amz-acl", "private")
setDummyAuthHeader(request)
// set an invalid date
request.Header.Set("Date", "asfasdfadf")
@ -397,16 +362,15 @@ func (s *MyAPIDonutCacheSuite) TestDateFormat(c *C) {
"The difference between the request time and the server's time is too large.", http.StatusForbidden)
request.Header.Set("Date", time.Now().UTC().Format(http.TimeFormat))
setDummyAuthHeader(request)
response, err = client.Do(request)
c.Assert(response.StatusCode, Equals, http.StatusOK)
}
*/
func (s *MyAPIDonutCacheSuite) TestXMLNameNotInBucketListJson(c *C) {
request, err := http.NewRequest("GET", testAPIDonutCacheServer.URL+"/", nil)
c.Assert(err, IsNil)
request.Header.Add("Accept", "application/json")
setDummyAuthHeader(request)
client := http.Client{}
response, err := client.Do(request)
@ -422,7 +386,6 @@ func (s *MyAPIDonutCacheSuite) TestXMLNameNotInObjectListJson(c *C) {
request, err := http.NewRequest("PUT", testAPIDonutCacheServer.URL+"/xmlnamenotinobjectlistjson", nil)
c.Assert(err, IsNil)
request.Header.Add("Accept", "application/json")
setDummyAuthHeader(request)
client := http.Client{}
response, err := client.Do(request)
@ -432,7 +395,6 @@ func (s *MyAPIDonutCacheSuite) TestXMLNameNotInObjectListJson(c *C) {
request, err = http.NewRequest("GET", testAPIDonutCacheServer.URL+"/xmlnamenotinobjectlistjson", nil)
c.Assert(err, IsNil)
request.Header.Add("Accept", "application/json")
setDummyAuthHeader(request)
client = http.Client{}
response, err = client.Do(request)
@ -447,7 +409,6 @@ func (s *MyAPIDonutCacheSuite) TestXMLNameNotInObjectListJson(c *C) {
func (s *MyAPIDonutCacheSuite) TestContentTypePersists(c *C) {
request, err := http.NewRequest("PUT", testAPIDonutCacheServer.URL+"/contenttype-persists", nil)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client := http.Client{}
response, err := client.Do(request)
@ -457,7 +418,6 @@ func (s *MyAPIDonutCacheSuite) TestContentTypePersists(c *C) {
request, err = http.NewRequest("PUT", testAPIDonutCacheServer.URL+"/contenttype-persists/one", bytes.NewBufferString("hello world"))
delete(request.Header, "Content-Type")
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client = http.Client{}
response, err = client.Do(request)
@ -466,7 +426,6 @@ func (s *MyAPIDonutCacheSuite) TestContentTypePersists(c *C) {
request, err = http.NewRequest("HEAD", testAPIDonutCacheServer.URL+"/contenttype-persists/one", nil)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
response, err = client.Do(request)
c.Assert(err, IsNil)
@ -474,7 +433,6 @@ func (s *MyAPIDonutCacheSuite) TestContentTypePersists(c *C) {
request, err = http.NewRequest("GET", testAPIDonutCacheServer.URL+"/contenttype-persists/one", nil)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client = http.Client{}
response, err = client.Do(request)
@ -486,7 +444,6 @@ func (s *MyAPIDonutCacheSuite) TestContentTypePersists(c *C) {
delete(request.Header, "Content-Type")
request.Header.Add("Content-Type", "application/json")
c.Assert(err, IsNil)
setDummyAuthHeader(request)
response, err = client.Do(request)
c.Assert(err, IsNil)
@ -494,7 +451,6 @@ func (s *MyAPIDonutCacheSuite) TestContentTypePersists(c *C) {
request, err = http.NewRequest("HEAD", testAPIDonutCacheServer.URL+"/contenttype-persists/two", nil)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
response, err = client.Do(request)
c.Assert(err, IsNil)
@ -502,7 +458,6 @@ func (s *MyAPIDonutCacheSuite) TestContentTypePersists(c *C) {
request, err = http.NewRequest("GET", testAPIDonutCacheServer.URL+"/contenttype-persists/two", nil)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
response, err = client.Do(request)
c.Assert(err, IsNil)
@ -512,7 +467,6 @@ func (s *MyAPIDonutCacheSuite) TestContentTypePersists(c *C) {
func (s *MyAPIDonutCacheSuite) TestPartialContent(c *C) {
request, err := http.NewRequest("PUT", testAPIDonutCacheServer.URL+"/partial-content", nil)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client := http.Client{}
response, err := client.Do(request)
@ -521,7 +475,6 @@ func (s *MyAPIDonutCacheSuite) TestPartialContent(c *C) {
request, err = http.NewRequest("PUT", testAPIDonutCacheServer.URL+"/partial-content/bar", bytes.NewBufferString("Hello World"))
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client = http.Client{}
response, err = client.Do(request)
@ -533,7 +486,6 @@ func (s *MyAPIDonutCacheSuite) TestPartialContent(c *C) {
c.Assert(err, IsNil)
request.Header.Add("Accept", "application/json")
request.Header.Add("Range", "bytes=6-7")
setDummyAuthHeader(request)
client = http.Client{}
response, err = client.Do(request)
@ -548,7 +500,6 @@ func (s *MyAPIDonutCacheSuite) TestPartialContent(c *C) {
func (s *MyAPIDonutCacheSuite) TestListObjectsHandlerErrors(c *C) {
request, err := http.NewRequest("GET", testAPIDonutCacheServer.URL+"/objecthandlererrors-.", nil)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client := http.Client{}
response, err := client.Do(request)
@ -557,7 +508,6 @@ func (s *MyAPIDonutCacheSuite) TestListObjectsHandlerErrors(c *C) {
request, err = http.NewRequest("GET", testAPIDonutCacheServer.URL+"/objecthandlererrors", nil)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client = http.Client{}
response, err = client.Do(request)
@ -569,7 +519,6 @@ func (s *MyAPIDonutCacheSuite) TestPutBucketErrors(c *C) {
request, err := http.NewRequest("PUT", testAPIDonutCacheServer.URL+"/putbucket-.", nil)
c.Assert(err, IsNil)
request.Header.Add("x-amz-acl", "private")
setDummyAuthHeader(request)
client := http.Client{}
response, err := client.Do(request)
@ -579,7 +528,6 @@ func (s *MyAPIDonutCacheSuite) TestPutBucketErrors(c *C) {
request, err = http.NewRequest("PUT", testAPIDonutCacheServer.URL+"/putbucket", nil)
c.Assert(err, IsNil)
request.Header.Add("x-amz-acl", "private")
setDummyAuthHeader(request)
client = http.Client{}
response, err = client.Do(request)
@ -589,7 +537,6 @@ func (s *MyAPIDonutCacheSuite) TestPutBucketErrors(c *C) {
request, err = http.NewRequest("PUT", testAPIDonutCacheServer.URL+"/putbucket", nil)
c.Assert(err, IsNil)
request.Header.Add("x-amz-acl", "private")
setDummyAuthHeader(request)
response, err = client.Do(request)
c.Assert(err, IsNil)
@ -598,7 +545,6 @@ func (s *MyAPIDonutCacheSuite) TestPutBucketErrors(c *C) {
request, err = http.NewRequest("PUT", testAPIDonutCacheServer.URL+"/putbucket?acl", nil)
c.Assert(err, IsNil)
request.Header.Add("x-amz-acl", "unknown")
setDummyAuthHeader(request)
response, err = client.Do(request)
c.Assert(err, IsNil)
@ -608,7 +554,6 @@ func (s *MyAPIDonutCacheSuite) TestPutBucketErrors(c *C) {
func (s *MyAPIDonutCacheSuite) TestGetObjectErrors(c *C) {
request, err := http.NewRequest("GET", testAPIDonutCacheServer.URL+"/getobjecterrors", nil)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client := http.Client{}
response, err := client.Do(request)
@ -617,7 +562,6 @@ func (s *MyAPIDonutCacheSuite) TestGetObjectErrors(c *C) {
request, err = http.NewRequest("PUT", testAPIDonutCacheServer.URL+"/getobjecterrors", nil)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client = http.Client{}
response, err = client.Do(request)
@ -626,7 +570,6 @@ func (s *MyAPIDonutCacheSuite) TestGetObjectErrors(c *C) {
request, err = http.NewRequest("GET", testAPIDonutCacheServer.URL+"/getobjecterrors/bar", nil)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client = http.Client{}
response, err = client.Do(request)
@ -635,7 +578,6 @@ func (s *MyAPIDonutCacheSuite) TestGetObjectErrors(c *C) {
request, err = http.NewRequest("GET", testAPIDonutCacheServer.URL+"/getobjecterrors-./bar", nil)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
response, err = client.Do(request)
c.Assert(err, IsNil)
@ -646,7 +588,6 @@ func (s *MyAPIDonutCacheSuite) TestGetObjectErrors(c *C) {
func (s *MyAPIDonutCacheSuite) TestGetObjectRangeErrors(c *C) {
request, err := http.NewRequest("PUT", testAPIDonutCacheServer.URL+"/getobjectrangeerrors", nil)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client := http.Client{}
response, err := client.Do(request)
@ -655,7 +596,6 @@ func (s *MyAPIDonutCacheSuite) TestGetObjectRangeErrors(c *C) {
request, err = http.NewRequest("PUT", testAPIDonutCacheServer.URL+"/getobjectrangeerrors/bar", bytes.NewBufferString("Hello World"))
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client = http.Client{}
response, err = client.Do(request)
@ -665,7 +605,6 @@ func (s *MyAPIDonutCacheSuite) TestGetObjectRangeErrors(c *C) {
request, err = http.NewRequest("GET", testAPIDonutCacheServer.URL+"/getobjectrangeerrors/bar", nil)
request.Header.Add("Range", "bytes=7-6")
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client = http.Client{}
response, err = client.Do(request)
@ -676,7 +615,6 @@ func (s *MyAPIDonutCacheSuite) TestGetObjectRangeErrors(c *C) {
func (s *MyAPIDonutCacheSuite) TestObjectMultipartAbort(c *C) {
request, err := http.NewRequest("PUT", testAPIDonutCacheServer.URL+"/objectmultipartabort", nil)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client := http.Client{}
response, err := client.Do(request)
@ -685,13 +623,12 @@ func (s *MyAPIDonutCacheSuite) TestObjectMultipartAbort(c *C) {
request, err = http.NewRequest("POST", testAPIDonutCacheServer.URL+"/objectmultipartabort/object?uploads", bytes.NewBufferString(""))
c.Assert(err, IsNil)
setDummyAuthHeader(request)
response, err = client.Do(request)
c.Assert(response.StatusCode, Equals, http.StatusOK)
decoder := xml.NewDecoder(response.Body)
newResponse := &api.InitiateMultipartUploadResult{}
newResponse := &api.InitiateMultipartUploadResponse{}
err = decoder.Decode(newResponse)
c.Assert(err, IsNil)
@ -700,7 +637,6 @@ func (s *MyAPIDonutCacheSuite) TestObjectMultipartAbort(c *C) {
request, err = http.NewRequest("PUT", testAPIDonutCacheServer.URL+"/objectmultipartabort/object?uploadId="+uploadID+"&partNumber=1", bytes.NewBufferString("hello world"))
c.Assert(err, IsNil)
setDummyAuthHeader(request)
response1, err := client.Do(request)
c.Assert(err, IsNil)
@ -708,7 +644,6 @@ func (s *MyAPIDonutCacheSuite) TestObjectMultipartAbort(c *C) {
request, err = http.NewRequest("PUT", testAPIDonutCacheServer.URL+"/objectmultipartabort/object?uploadId="+uploadID+"&partNumber=2", bytes.NewBufferString("hello world"))
c.Assert(err, IsNil)
setDummyAuthHeader(request)
response2, err := client.Do(request)
c.Assert(err, IsNil)
@ -716,7 +651,6 @@ func (s *MyAPIDonutCacheSuite) TestObjectMultipartAbort(c *C) {
request, err = http.NewRequest("DELETE", testAPIDonutCacheServer.URL+"/objectmultipartabort/object?uploadId="+uploadID, nil)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
response3, err := client.Do(request)
c.Assert(err, IsNil)
@ -726,7 +660,6 @@ func (s *MyAPIDonutCacheSuite) TestObjectMultipartAbort(c *C) {
func (s *MyAPIDonutCacheSuite) TestBucketMultipartList(c *C) {
request, err := http.NewRequest("PUT", testAPIDonutCacheServer.URL+"/bucketmultipartlist", bytes.NewBufferString(""))
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client := http.Client{}
response, err := client.Do(request)
@ -735,13 +668,12 @@ func (s *MyAPIDonutCacheSuite) TestBucketMultipartList(c *C) {
request, err = http.NewRequest("POST", testAPIDonutCacheServer.URL+"/bucketmultipartlist/object?uploads", bytes.NewBufferString(""))
c.Assert(err, IsNil)
setDummyAuthHeader(request)
response, err = client.Do(request)
c.Assert(response.StatusCode, Equals, http.StatusOK)
decoder := xml.NewDecoder(response.Body)
newResponse := &api.InitiateMultipartUploadResult{}
newResponse := &api.InitiateMultipartUploadResponse{}
err = decoder.Decode(newResponse)
c.Assert(err, IsNil)
@ -750,7 +682,6 @@ func (s *MyAPIDonutCacheSuite) TestBucketMultipartList(c *C) {
request, err = http.NewRequest("PUT", testAPIDonutCacheServer.URL+"/bucketmultipartlist/object?uploadId="+uploadID+"&partNumber=1", bytes.NewBufferString("hello world"))
c.Assert(err, IsNil)
setDummyAuthHeader(request)
response1, err := client.Do(request)
c.Assert(err, IsNil)
@ -758,7 +689,6 @@ func (s *MyAPIDonutCacheSuite) TestBucketMultipartList(c *C) {
request, err = http.NewRequest("PUT", testAPIDonutCacheServer.URL+"/bucketmultipartlist/object?uploadId="+uploadID+"&partNumber=2", bytes.NewBufferString("hello world"))
c.Assert(err, IsNil)
setDummyAuthHeader(request)
response2, err := client.Do(request)
c.Assert(err, IsNil)
@ -766,7 +696,6 @@ func (s *MyAPIDonutCacheSuite) TestBucketMultipartList(c *C) {
request, err = http.NewRequest("GET", testAPIDonutCacheServer.URL+"/bucketmultipartlist?uploads", nil)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
response3, err := client.Do(request)
c.Assert(err, IsNil)
@ -782,7 +711,6 @@ func (s *MyAPIDonutCacheSuite) TestBucketMultipartList(c *C) {
func (s *MyAPIDonutCacheSuite) TestObjectMultipartList(c *C) {
request, err := http.NewRequest("PUT", testAPIDonutCacheServer.URL+"/objectmultipartlist", bytes.NewBufferString(""))
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client := http.Client{}
response, err := client.Do(request)
@ -791,13 +719,12 @@ func (s *MyAPIDonutCacheSuite) TestObjectMultipartList(c *C) {
request, err = http.NewRequest("POST", testAPIDonutCacheServer.URL+"/objectmultipartlist/object?uploads", bytes.NewBufferString(""))
c.Assert(err, IsNil)
setDummyAuthHeader(request)
response, err = client.Do(request)
c.Assert(response.StatusCode, Equals, http.StatusOK)
decoder := xml.NewDecoder(response.Body)
newResponse := &api.InitiateMultipartUploadResult{}
newResponse := &api.InitiateMultipartUploadResponse{}
err = decoder.Decode(newResponse)
c.Assert(err, IsNil)
@ -806,7 +733,6 @@ func (s *MyAPIDonutCacheSuite) TestObjectMultipartList(c *C) {
request, err = http.NewRequest("PUT", testAPIDonutCacheServer.URL+"/objectmultipartlist/object?uploadId="+uploadID+"&partNumber=1", bytes.NewBufferString("hello world"))
c.Assert(err, IsNil)
setDummyAuthHeader(request)
response1, err := client.Do(request)
c.Assert(err, IsNil)
@ -814,7 +740,6 @@ func (s *MyAPIDonutCacheSuite) TestObjectMultipartList(c *C) {
request, err = http.NewRequest("PUT", testAPIDonutCacheServer.URL+"/objectmultipartlist/object?uploadId="+uploadID+"&partNumber=2", bytes.NewBufferString("hello world"))
c.Assert(err, IsNil)
setDummyAuthHeader(request)
response2, err := client.Do(request)
c.Assert(err, IsNil)
@ -822,7 +747,6 @@ func (s *MyAPIDonutCacheSuite) TestObjectMultipartList(c *C) {
request, err = http.NewRequest("GET", testAPIDonutCacheServer.URL+"/objectmultipartlist/object?uploadId="+uploadID, nil)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
response3, err := client.Do(request)
c.Assert(err, IsNil)
@ -833,7 +757,6 @@ func (s *MyAPIDonutCacheSuite) TestObjectMultipartList(c *C) {
func (s *MyAPIDonutCacheSuite) TestObjectMultipart(c *C) {
request, err := http.NewRequest("PUT", testAPIDonutCacheServer.URL+"/objectmultiparts", nil)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client := http.Client{}
response, err := client.Do(request)
@ -842,7 +765,6 @@ func (s *MyAPIDonutCacheSuite) TestObjectMultipart(c *C) {
request, err = http.NewRequest("POST", testAPIDonutCacheServer.URL+"/objectmultiparts/object?uploads", nil)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client = http.Client{}
response, err = client.Do(request)
@ -850,7 +772,7 @@ func (s *MyAPIDonutCacheSuite) TestObjectMultipart(c *C) {
c.Assert(response.StatusCode, Equals, http.StatusOK)
decoder := xml.NewDecoder(response.Body)
newResponse := &api.InitiateMultipartUploadResult{}
newResponse := &api.InitiateMultipartUploadResponse{}
err = decoder.Decode(newResponse)
c.Assert(err, IsNil)
@ -859,7 +781,6 @@ func (s *MyAPIDonutCacheSuite) TestObjectMultipart(c *C) {
request, err = http.NewRequest("PUT", testAPIDonutCacheServer.URL+"/objectmultiparts/object?uploadId="+uploadID+"&partNumber=1", bytes.NewBufferString("hello world"))
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client = http.Client{}
response1, err := client.Do(request)
@ -868,7 +789,6 @@ func (s *MyAPIDonutCacheSuite) TestObjectMultipart(c *C) {
request, err = http.NewRequest("PUT", testAPIDonutCacheServer.URL+"/objectmultiparts/object?uploadId="+uploadID+"&partNumber=2", bytes.NewBufferString("hello world"))
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client = http.Client{}
response2, err := client.Do(request)
@ -876,8 +796,8 @@ func (s *MyAPIDonutCacheSuite) TestObjectMultipart(c *C) {
c.Assert(response2.StatusCode, Equals, http.StatusOK)
// complete multipart upload
completeUploads := &api.CompleteMultipartUpload{
Part: []api.Part{
completeUploads := &donut.CompleteMultipartUpload{
Part: []donut.CompletePart{
{
PartNumber: 1,
ETag: response1.Header.Get("ETag"),
@ -895,7 +815,6 @@ func (s *MyAPIDonutCacheSuite) TestObjectMultipart(c *C) {
request, err = http.NewRequest("POST", testAPIDonutCacheServer.URL+"/objectmultiparts/object?uploadId="+uploadID, &completeBuffer)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
response, err = client.Do(request)
c.Assert(err, IsNil)
@ -903,7 +822,6 @@ func (s *MyAPIDonutCacheSuite) TestObjectMultipart(c *C) {
request, err = http.NewRequest("GET", testAPIDonutCacheServer.URL+"/objectmultiparts/object", nil)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
response, err = client.Do(request)
c.Assert(err, IsNil)

View File

@ -24,7 +24,6 @@ import (
"strconv"
"strings"
"testing"
"time"
"encoding/xml"
"net/http"
@ -88,7 +87,6 @@ func (s *MyAPIDonutSuite) TearDownSuite(c *C) {
func (s *MyAPIDonutSuite) TestNonExistantBucket(c *C) {
request, err := http.NewRequest("HEAD", testAPIDonutServer.URL+"/nonexistantbucket", nil)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client := http.Client{}
response, err := client.Do(request)
@ -99,7 +97,6 @@ func (s *MyAPIDonutSuite) TestNonExistantBucket(c *C) {
func (s *MyAPIDonutSuite) TestEmptyObject(c *C) {
request, err := http.NewRequest("PUT", testAPIDonutServer.URL+"/emptyobject", nil)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client := http.Client{}
response, err := client.Do(request)
@ -108,7 +105,6 @@ func (s *MyAPIDonutSuite) TestEmptyObject(c *C) {
request, err = http.NewRequest("PUT", testAPIDonutServer.URL+"/emptyobject/object", nil)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client = http.Client{}
response, err = client.Do(request)
@ -117,7 +113,6 @@ func (s *MyAPIDonutSuite) TestEmptyObject(c *C) {
request, err = http.NewRequest("GET", testAPIDonutServer.URL+"/emptyobject/object", nil)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client = http.Client{}
response, err = client.Do(request)
@ -133,7 +128,6 @@ func (s *MyAPIDonutSuite) TestEmptyObject(c *C) {
func (s *MyAPIDonutSuite) TestBucket(c *C) {
request, err := http.NewRequest("PUT", testAPIDonutServer.URL+"/bucket", nil)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client := http.Client{}
response, err := client.Do(request)
@ -142,7 +136,6 @@ func (s *MyAPIDonutSuite) TestBucket(c *C) {
request, err = http.NewRequest("HEAD", testAPIDonutServer.URL+"/bucket", nil)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client = http.Client{}
response, err = client.Do(request)
@ -154,7 +147,6 @@ func (s *MyAPIDonutSuite) TestObject(c *C) {
buffer := bytes.NewBufferString("hello world")
request, err := http.NewRequest("PUT", testAPIDonutServer.URL+"/testobject", nil)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client := http.Client{}
response, err := client.Do(request)
@ -163,7 +155,6 @@ func (s *MyAPIDonutSuite) TestObject(c *C) {
request, err = http.NewRequest("PUT", testAPIDonutServer.URL+"/testobject/object", buffer)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client = http.Client{}
response, err = client.Do(request)
@ -172,7 +163,6 @@ func (s *MyAPIDonutSuite) TestObject(c *C) {
request, err = http.NewRequest("GET", testAPIDonutServer.URL+"/testobject/object", nil)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client = http.Client{}
response, err = client.Do(request)
@ -188,7 +178,6 @@ func (s *MyAPIDonutSuite) TestObject(c *C) {
func (s *MyAPIDonutSuite) TestMultipleObjects(c *C) {
request, err := http.NewRequest("PUT", testAPIDonutServer.URL+"/multipleobjects", nil)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client := http.Client{}
response, err := client.Do(request)
@ -197,7 +186,6 @@ func (s *MyAPIDonutSuite) TestMultipleObjects(c *C) {
request, err = http.NewRequest("GET", testAPIDonutServer.URL+"/multipleobjects/object", nil)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client = http.Client{}
response, err = client.Do(request)
@ -210,7 +198,6 @@ func (s *MyAPIDonutSuite) TestMultipleObjects(c *C) {
buffer1 := bytes.NewBufferString("hello one")
request, err = http.NewRequest("PUT", testAPIDonutServer.URL+"/multipleobjects/object1", buffer1)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client = http.Client{}
response, err = client.Do(request)
@ -219,7 +206,6 @@ func (s *MyAPIDonutSuite) TestMultipleObjects(c *C) {
request, err = http.NewRequest("GET", testAPIDonutServer.URL+"/multipleobjects/object1", nil)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client = http.Client{}
response, err = client.Do(request)
@ -234,7 +220,6 @@ func (s *MyAPIDonutSuite) TestMultipleObjects(c *C) {
buffer2 := bytes.NewBufferString("hello two")
request, err = http.NewRequest("PUT", testAPIDonutServer.URL+"/multipleobjects/object2", buffer2)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client = http.Client{}
response, err = client.Do(request)
@ -243,7 +228,6 @@ func (s *MyAPIDonutSuite) TestMultipleObjects(c *C) {
request, err = http.NewRequest("GET", testAPIDonutServer.URL+"/multipleobjects/object2", nil)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client = http.Client{}
response, err = client.Do(request)
@ -258,7 +242,6 @@ func (s *MyAPIDonutSuite) TestMultipleObjects(c *C) {
buffer3 := bytes.NewBufferString("hello three")
request, err = http.NewRequest("PUT", testAPIDonutServer.URL+"/multipleobjects/object3", buffer3)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client = http.Client{}
response, err = client.Do(request)
@ -267,7 +250,6 @@ func (s *MyAPIDonutSuite) TestMultipleObjects(c *C) {
request, err = http.NewRequest("GET", testAPIDonutServer.URL+"/multipleobjects/object3", nil)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client = http.Client{}
response, err = client.Do(request)
@ -283,7 +265,6 @@ func (s *MyAPIDonutSuite) TestMultipleObjects(c *C) {
func (s *MyAPIDonutSuite) TestNotImplemented(c *C) {
request, err := http.NewRequest("GET", testAPIDonutServer.URL+"/bucket/object?policy", nil)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client := http.Client{}
response, err := client.Do(request)
@ -295,7 +276,6 @@ func (s *MyAPIDonutSuite) TestNotImplemented(c *C) {
func (s *MyAPIDonutSuite) TestHeader(c *C) {
request, err := http.NewRequest("GET", testAPIDonutServer.URL+"/bucket/object", nil)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client := http.Client{}
response, err := client.Do(request)
@ -308,7 +288,6 @@ func (s *MyAPIDonutSuite) TestPutBucket(c *C) {
request, err := http.NewRequest("PUT", testAPIDonutServer.URL+"/put-bucket", nil)
c.Assert(err, IsNil)
request.Header.Add("x-amz-acl", "private")
setDummyAuthHeader(request)
client := http.Client{}
response, err := client.Do(request)
@ -320,7 +299,6 @@ func (s *MyAPIDonutSuite) TestPutObject(c *C) {
request, err := http.NewRequest("PUT", testAPIDonutServer.URL+"/put-object", nil)
c.Assert(err, IsNil)
request.Header.Add("x-amz-acl", "private")
setDummyAuthHeader(request)
client := http.Client{}
response, err := client.Do(request)
@ -329,7 +307,6 @@ func (s *MyAPIDonutSuite) TestPutObject(c *C) {
request, err = http.NewRequest("PUT", testAPIDonutServer.URL+"/put-object/object", bytes.NewBufferString("hello world"))
c.Assert(err, IsNil)
setDummyAuthHeader(request)
response, err = client.Do(request)
c.Assert(err, IsNil)
@ -339,7 +316,6 @@ func (s *MyAPIDonutSuite) TestPutObject(c *C) {
func (s *MyAPIDonutSuite) TestListBuckets(c *C) {
request, err := http.NewRequest("GET", testAPIDonutServer.URL+"/", nil)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client := http.Client{}
response, err := client.Do(request)
@ -355,7 +331,6 @@ func (s *MyAPIDonutSuite) TestListBuckets(c *C) {
func (s *MyAPIDonutSuite) TestNotBeAbleToCreateObjectInNonexistantBucket(c *C) {
request, err := http.NewRequest("PUT", testAPIDonutServer.URL+"/innonexistantbucket/object", bytes.NewBufferString("hello world"))
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client := http.Client{}
response, err := client.Do(request)
@ -367,7 +342,6 @@ func (s *MyAPIDonutSuite) TestHeadOnObject(c *C) {
request, err := http.NewRequest("PUT", testAPIDonutServer.URL+"/headonobject", nil)
c.Assert(err, IsNil)
request.Header.Add("x-amz-acl", "private")
setDummyAuthHeader(request)
client := http.Client{}
response, err := client.Do(request)
@ -376,7 +350,6 @@ func (s *MyAPIDonutSuite) TestHeadOnObject(c *C) {
request, err = http.NewRequest("PUT", testAPIDonutServer.URL+"/headonobject/object1", bytes.NewBufferString("hello world"))
c.Assert(err, IsNil)
setDummyAuthHeader(request)
response, err = client.Do(request)
c.Assert(err, IsNil)
@ -384,7 +357,6 @@ func (s *MyAPIDonutSuite) TestHeadOnObject(c *C) {
request, err = http.NewRequest("HEAD", testAPIDonutServer.URL+"/headonobject/object1", nil)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
response, err = client.Do(request)
c.Assert(err, IsNil)
@ -395,7 +367,6 @@ func (s *MyAPIDonutSuite) TestHeadOnBucket(c *C) {
request, err := http.NewRequest("PUT", testAPIDonutServer.URL+"/headonbucket", nil)
c.Assert(err, IsNil)
request.Header.Add("x-amz-acl", "private")
setDummyAuthHeader(request)
client := http.Client{}
response, err := client.Do(request)
@ -404,18 +375,17 @@ func (s *MyAPIDonutSuite) TestHeadOnBucket(c *C) {
request, err = http.NewRequest("HEAD", testAPIDonutServer.URL+"/headonbucket", nil)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
response, err = client.Do(request)
c.Assert(err, IsNil)
c.Assert(response.StatusCode, Equals, http.StatusOK)
}
/*
func (s *MyAPIDonutSuite) TestDateFormat(c *C) {
request, err := http.NewRequest("PUT", testAPIDonutServer.URL+"/dateformat", nil)
c.Assert(err, IsNil)
request.Header.Add("x-amz-acl", "private")
setDummyAuthHeader(request)
// set an invalid date
request.Header.Set("Date", "asfasdfadf")
@ -427,16 +397,16 @@ func (s *MyAPIDonutSuite) TestDateFormat(c *C) {
"The difference between the request time and the server's time is too large.", http.StatusForbidden)
request.Header.Set("Date", time.Now().UTC().Format(http.TimeFormat))
setDummyAuthHeader(request)
response, err = client.Do(request)
c.Assert(response.StatusCode, Equals, http.StatusOK)
}
*/
func (s *MyAPIDonutSuite) TestXMLNameNotInBucketListJson(c *C) {
request, err := http.NewRequest("GET", testAPIDonutServer.URL+"/", nil)
c.Assert(err, IsNil)
request.Header.Add("Accept", "application/json")
setDummyAuthHeader(request)
client := http.Client{}
response, err := client.Do(request)
@ -452,7 +422,6 @@ func (s *MyAPIDonutSuite) TestXMLNameNotInObjectListJson(c *C) {
request, err := http.NewRequest("PUT", testAPIDonutServer.URL+"/xmlnamenotinobjectlistjson", nil)
c.Assert(err, IsNil)
request.Header.Add("Accept", "application/json")
setDummyAuthHeader(request)
client := http.Client{}
response, err := client.Do(request)
@ -462,7 +431,6 @@ func (s *MyAPIDonutSuite) TestXMLNameNotInObjectListJson(c *C) {
request, err = http.NewRequest("GET", testAPIDonutServer.URL+"/xmlnamenotinobjectlistjson", nil)
c.Assert(err, IsNil)
request.Header.Add("Accept", "application/json")
setDummyAuthHeader(request)
client = http.Client{}
response, err = client.Do(request)
@ -477,7 +445,6 @@ func (s *MyAPIDonutSuite) TestXMLNameNotInObjectListJson(c *C) {
func (s *MyAPIDonutSuite) TestContentTypePersists(c *C) {
request, err := http.NewRequest("PUT", testAPIDonutServer.URL+"/contenttype-persists", nil)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client := http.Client{}
response, err := client.Do(request)
@ -487,7 +454,6 @@ func (s *MyAPIDonutSuite) TestContentTypePersists(c *C) {
request, err = http.NewRequest("PUT", testAPIDonutServer.URL+"/contenttype-persists/one", bytes.NewBufferString("hello world"))
delete(request.Header, "Content-Type")
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client = http.Client{}
response, err = client.Do(request)
@ -496,7 +462,6 @@ func (s *MyAPIDonutSuite) TestContentTypePersists(c *C) {
request, err = http.NewRequest("HEAD", testAPIDonutServer.URL+"/contenttype-persists/one", nil)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
response, err = client.Do(request)
c.Assert(err, IsNil)
@ -504,7 +469,6 @@ func (s *MyAPIDonutSuite) TestContentTypePersists(c *C) {
request, err = http.NewRequest("GET", testAPIDonutServer.URL+"/contenttype-persists/one", nil)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client = http.Client{}
response, err = client.Do(request)
@ -516,7 +480,6 @@ func (s *MyAPIDonutSuite) TestContentTypePersists(c *C) {
delete(request.Header, "Content-Type")
request.Header.Add("Content-Type", "application/json")
c.Assert(err, IsNil)
setDummyAuthHeader(request)
response, err = client.Do(request)
c.Assert(err, IsNil)
@ -524,7 +487,6 @@ func (s *MyAPIDonutSuite) TestContentTypePersists(c *C) {
request, err = http.NewRequest("HEAD", testAPIDonutServer.URL+"/contenttype-persists/two", nil)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
response, err = client.Do(request)
c.Assert(err, IsNil)
@ -532,7 +494,6 @@ func (s *MyAPIDonutSuite) TestContentTypePersists(c *C) {
request, err = http.NewRequest("GET", testAPIDonutServer.URL+"/contenttype-persists/two", nil)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
response, err = client.Do(request)
c.Assert(err, IsNil)
@ -542,7 +503,6 @@ func (s *MyAPIDonutSuite) TestContentTypePersists(c *C) {
func (s *MyAPIDonutSuite) TestPartialContent(c *C) {
request, err := http.NewRequest("PUT", testAPIDonutServer.URL+"/partial-content", nil)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client := http.Client{}
response, err := client.Do(request)
@ -551,7 +511,6 @@ func (s *MyAPIDonutSuite) TestPartialContent(c *C) {
request, err = http.NewRequest("PUT", testAPIDonutServer.URL+"/partial-content/bar", bytes.NewBufferString("Hello World"))
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client = http.Client{}
response, err = client.Do(request)
@ -563,7 +522,6 @@ func (s *MyAPIDonutSuite) TestPartialContent(c *C) {
c.Assert(err, IsNil)
request.Header.Add("Accept", "application/json")
request.Header.Add("Range", "bytes=6-7")
setDummyAuthHeader(request)
client = http.Client{}
response, err = client.Do(request)
@ -578,7 +536,6 @@ func (s *MyAPIDonutSuite) TestPartialContent(c *C) {
func (s *MyAPIDonutSuite) TestListObjectsHandlerErrors(c *C) {
request, err := http.NewRequest("GET", testAPIDonutServer.URL+"/objecthandlererrors-.", nil)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client := http.Client{}
response, err := client.Do(request)
@ -587,7 +544,6 @@ func (s *MyAPIDonutSuite) TestListObjectsHandlerErrors(c *C) {
request, err = http.NewRequest("GET", testAPIDonutServer.URL+"/objecthandlererrors", nil)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client = http.Client{}
response, err = client.Do(request)
@ -599,7 +555,6 @@ func (s *MyAPIDonutSuite) TestPutBucketErrors(c *C) {
request, err := http.NewRequest("PUT", testAPIDonutServer.URL+"/putbucket-.", nil)
c.Assert(err, IsNil)
request.Header.Add("x-amz-acl", "private")
setDummyAuthHeader(request)
client := http.Client{}
response, err := client.Do(request)
@ -609,7 +564,6 @@ func (s *MyAPIDonutSuite) TestPutBucketErrors(c *C) {
request, err = http.NewRequest("PUT", testAPIDonutServer.URL+"/putbucket", nil)
c.Assert(err, IsNil)
request.Header.Add("x-amz-acl", "private")
setDummyAuthHeader(request)
client = http.Client{}
response, err = client.Do(request)
@ -619,7 +573,6 @@ func (s *MyAPIDonutSuite) TestPutBucketErrors(c *C) {
request, err = http.NewRequest("PUT", testAPIDonutServer.URL+"/putbucket", nil)
c.Assert(err, IsNil)
request.Header.Add("x-amz-acl", "private")
setDummyAuthHeader(request)
response, err = client.Do(request)
c.Assert(err, IsNil)
@ -628,7 +581,6 @@ func (s *MyAPIDonutSuite) TestPutBucketErrors(c *C) {
request, err = http.NewRequest("PUT", testAPIDonutServer.URL+"/putbucket?acl", nil)
c.Assert(err, IsNil)
request.Header.Add("x-amz-acl", "unknown")
setDummyAuthHeader(request)
response, err = client.Do(request)
c.Assert(err, IsNil)
@ -638,7 +590,6 @@ func (s *MyAPIDonutSuite) TestPutBucketErrors(c *C) {
func (s *MyAPIDonutSuite) TestGetObjectErrors(c *C) {
request, err := http.NewRequest("GET", testAPIDonutServer.URL+"/getobjecterrors", nil)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client := http.Client{}
response, err := client.Do(request)
@ -647,7 +598,6 @@ func (s *MyAPIDonutSuite) TestGetObjectErrors(c *C) {
request, err = http.NewRequest("PUT", testAPIDonutServer.URL+"/getobjecterrors", nil)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client = http.Client{}
response, err = client.Do(request)
@ -656,7 +606,6 @@ func (s *MyAPIDonutSuite) TestGetObjectErrors(c *C) {
request, err = http.NewRequest("GET", testAPIDonutServer.URL+"/getobjecterrors/bar", nil)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client = http.Client{}
response, err = client.Do(request)
@ -665,7 +614,6 @@ func (s *MyAPIDonutSuite) TestGetObjectErrors(c *C) {
request, err = http.NewRequest("GET", testAPIDonutServer.URL+"/getobjecterrors-./bar", nil)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
response, err = client.Do(request)
c.Assert(err, IsNil)
@ -676,7 +624,6 @@ func (s *MyAPIDonutSuite) TestGetObjectErrors(c *C) {
func (s *MyAPIDonutSuite) TestGetObjectRangeErrors(c *C) {
request, err := http.NewRequest("PUT", testAPIDonutServer.URL+"/getobjectrangeerrors", nil)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client := http.Client{}
response, err := client.Do(request)
@ -685,7 +632,6 @@ func (s *MyAPIDonutSuite) TestGetObjectRangeErrors(c *C) {
request, err = http.NewRequest("PUT", testAPIDonutServer.URL+"/getobjectrangeerrors/bar", bytes.NewBufferString("Hello World"))
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client = http.Client{}
response, err = client.Do(request)
@ -695,7 +641,6 @@ func (s *MyAPIDonutSuite) TestGetObjectRangeErrors(c *C) {
request, err = http.NewRequest("GET", testAPIDonutServer.URL+"/getobjectrangeerrors/bar", nil)
request.Header.Add("Range", "bytes=7-6")
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client = http.Client{}
response, err = client.Do(request)
@ -706,7 +651,6 @@ func (s *MyAPIDonutSuite) TestGetObjectRangeErrors(c *C) {
func (s *MyAPIDonutSuite) TestObjectMultipartAbort(c *C) {
request, err := http.NewRequest("PUT", testAPIDonutServer.URL+"/objectmultipartabort", nil)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client := http.Client{}
response, err := client.Do(request)
@ -715,13 +659,12 @@ func (s *MyAPIDonutSuite) TestObjectMultipartAbort(c *C) {
request, err = http.NewRequest("POST", testAPIDonutServer.URL+"/objectmultipartabort/object?uploads", bytes.NewBufferString(""))
c.Assert(err, IsNil)
setDummyAuthHeader(request)
response, err = client.Do(request)
c.Assert(response.StatusCode, Equals, http.StatusOK)
decoder := xml.NewDecoder(response.Body)
newResponse := &api.InitiateMultipartUploadResult{}
newResponse := &api.InitiateMultipartUploadResponse{}
err = decoder.Decode(newResponse)
c.Assert(err, IsNil)
@ -730,7 +673,6 @@ func (s *MyAPIDonutSuite) TestObjectMultipartAbort(c *C) {
request, err = http.NewRequest("PUT", testAPIDonutServer.URL+"/objectmultipartabort/object?uploadId="+uploadID+"&partNumber=1", bytes.NewBufferString("hello world"))
c.Assert(err, IsNil)
setDummyAuthHeader(request)
response1, err := client.Do(request)
c.Assert(err, IsNil)
@ -738,7 +680,6 @@ func (s *MyAPIDonutSuite) TestObjectMultipartAbort(c *C) {
request, err = http.NewRequest("PUT", testAPIDonutServer.URL+"/objectmultipartabort/object?uploadId="+uploadID+"&partNumber=2", bytes.NewBufferString("hello world"))
c.Assert(err, IsNil)
setDummyAuthHeader(request)
response2, err := client.Do(request)
c.Assert(err, IsNil)
@ -746,7 +687,6 @@ func (s *MyAPIDonutSuite) TestObjectMultipartAbort(c *C) {
request, err = http.NewRequest("DELETE", testAPIDonutServer.URL+"/objectmultipartabort/object?uploadId="+uploadID, nil)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
response3, err := client.Do(request)
c.Assert(err, IsNil)
@ -756,7 +696,6 @@ func (s *MyAPIDonutSuite) TestObjectMultipartAbort(c *C) {
func (s *MyAPIDonutSuite) TestBucketMultipartList(c *C) {
request, err := http.NewRequest("PUT", testAPIDonutServer.URL+"/bucketmultipartlist", bytes.NewBufferString(""))
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client := http.Client{}
response, err := client.Do(request)
@ -765,13 +704,12 @@ func (s *MyAPIDonutSuite) TestBucketMultipartList(c *C) {
request, err = http.NewRequest("POST", testAPIDonutServer.URL+"/bucketmultipartlist/object?uploads", bytes.NewBufferString(""))
c.Assert(err, IsNil)
setDummyAuthHeader(request)
response, err = client.Do(request)
c.Assert(response.StatusCode, Equals, http.StatusOK)
decoder := xml.NewDecoder(response.Body)
newResponse := &api.InitiateMultipartUploadResult{}
newResponse := &api.InitiateMultipartUploadResponse{}
err = decoder.Decode(newResponse)
c.Assert(err, IsNil)
@ -780,7 +718,6 @@ func (s *MyAPIDonutSuite) TestBucketMultipartList(c *C) {
request, err = http.NewRequest("PUT", testAPIDonutServer.URL+"/bucketmultipartlist/object?uploadId="+uploadID+"&partNumber=1", bytes.NewBufferString("hello world"))
c.Assert(err, IsNil)
setDummyAuthHeader(request)
response1, err := client.Do(request)
c.Assert(err, IsNil)
@ -788,7 +725,6 @@ func (s *MyAPIDonutSuite) TestBucketMultipartList(c *C) {
request, err = http.NewRequest("PUT", testAPIDonutServer.URL+"/bucketmultipartlist/object?uploadId="+uploadID+"&partNumber=2", bytes.NewBufferString("hello world"))
c.Assert(err, IsNil)
setDummyAuthHeader(request)
response2, err := client.Do(request)
c.Assert(err, IsNil)
@ -796,7 +732,6 @@ func (s *MyAPIDonutSuite) TestBucketMultipartList(c *C) {
request, err = http.NewRequest("GET", testAPIDonutServer.URL+"/bucketmultipartlist?uploads", nil)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
response3, err := client.Do(request)
c.Assert(err, IsNil)
@ -812,7 +747,6 @@ func (s *MyAPIDonutSuite) TestBucketMultipartList(c *C) {
func (s *MyAPIDonutSuite) TestObjectMultipartList(c *C) {
request, err := http.NewRequest("PUT", testAPIDonutServer.URL+"/objectmultipartlist", bytes.NewBufferString(""))
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client := http.Client{}
response, err := client.Do(request)
@ -821,13 +755,12 @@ func (s *MyAPIDonutSuite) TestObjectMultipartList(c *C) {
request, err = http.NewRequest("POST", testAPIDonutServer.URL+"/objectmultipartlist/object?uploads", bytes.NewBufferString(""))
c.Assert(err, IsNil)
setDummyAuthHeader(request)
response, err = client.Do(request)
c.Assert(response.StatusCode, Equals, http.StatusOK)
decoder := xml.NewDecoder(response.Body)
newResponse := &api.InitiateMultipartUploadResult{}
newResponse := &api.InitiateMultipartUploadResponse{}
err = decoder.Decode(newResponse)
c.Assert(err, IsNil)
@ -836,7 +769,6 @@ func (s *MyAPIDonutSuite) TestObjectMultipartList(c *C) {
request, err = http.NewRequest("PUT", testAPIDonutServer.URL+"/objectmultipartlist/object?uploadId="+uploadID+"&partNumber=1", bytes.NewBufferString("hello world"))
c.Assert(err, IsNil)
setDummyAuthHeader(request)
response1, err := client.Do(request)
c.Assert(err, IsNil)
@ -844,7 +776,6 @@ func (s *MyAPIDonutSuite) TestObjectMultipartList(c *C) {
request, err = http.NewRequest("PUT", testAPIDonutServer.URL+"/objectmultipartlist/object?uploadId="+uploadID+"&partNumber=2", bytes.NewBufferString("hello world"))
c.Assert(err, IsNil)
setDummyAuthHeader(request)
response2, err := client.Do(request)
c.Assert(err, IsNil)
@ -852,7 +783,6 @@ func (s *MyAPIDonutSuite) TestObjectMultipartList(c *C) {
request, err = http.NewRequest("GET", testAPIDonutServer.URL+"/objectmultipartlist/object?uploadId="+uploadID, nil)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
response3, err := client.Do(request)
c.Assert(err, IsNil)
@ -863,7 +793,6 @@ func (s *MyAPIDonutSuite) TestObjectMultipartList(c *C) {
func (s *MyAPIDonutSuite) TestObjectMultipart(c *C) {
request, err := http.NewRequest("PUT", testAPIDonutServer.URL+"/objectmultiparts", nil)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client := http.Client{}
response, err := client.Do(request)
@ -872,7 +801,6 @@ func (s *MyAPIDonutSuite) TestObjectMultipart(c *C) {
request, err = http.NewRequest("POST", testAPIDonutServer.URL+"/objectmultiparts/object?uploads", nil)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client = http.Client{}
response, err = client.Do(request)
@ -880,7 +808,7 @@ func (s *MyAPIDonutSuite) TestObjectMultipart(c *C) {
c.Assert(response.StatusCode, Equals, http.StatusOK)
decoder := xml.NewDecoder(response.Body)
newResponse := &api.InitiateMultipartUploadResult{}
newResponse := &api.InitiateMultipartUploadResponse{}
err = decoder.Decode(newResponse)
c.Assert(err, IsNil)
@ -889,7 +817,6 @@ func (s *MyAPIDonutSuite) TestObjectMultipart(c *C) {
request, err = http.NewRequest("PUT", testAPIDonutServer.URL+"/objectmultiparts/object?uploadId="+uploadID+"&partNumber=1", bytes.NewBufferString("hello world"))
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client = http.Client{}
response1, err := client.Do(request)
@ -898,7 +825,6 @@ func (s *MyAPIDonutSuite) TestObjectMultipart(c *C) {
request, err = http.NewRequest("PUT", testAPIDonutServer.URL+"/objectmultiparts/object?uploadId="+uploadID+"&partNumber=2", bytes.NewBufferString("hello world"))
c.Assert(err, IsNil)
setDummyAuthHeader(request)
client = http.Client{}
response2, err := client.Do(request)
@ -906,8 +832,8 @@ func (s *MyAPIDonutSuite) TestObjectMultipart(c *C) {
c.Assert(response2.StatusCode, Equals, http.StatusOK)
// complete multipart upload
completeUploads := &api.CompleteMultipartUpload{
Part: []api.Part{
completeUploads := &donut.CompleteMultipartUpload{
Part: []donut.CompletePart{
{
PartNumber: 1,
ETag: response1.Header.Get("ETag"),
@ -925,7 +851,6 @@ func (s *MyAPIDonutSuite) TestObjectMultipart(c *C) {
request, err = http.NewRequest("POST", testAPIDonutServer.URL+"/objectmultiparts/object?uploadId="+uploadID, &completeBuffer)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
response, err = client.Do(request)
c.Assert(err, IsNil)
@ -933,7 +858,6 @@ func (s *MyAPIDonutSuite) TestObjectMultipart(c *C) {
request, err = http.NewRequest("GET", testAPIDonutServer.URL+"/objectmultiparts/object", nil)
c.Assert(err, IsNil)
setDummyAuthHeader(request)
response, err = client.Do(request)
c.Assert(err, IsNil)