mirror of
https://github.com/minio/minio
synced 2024-11-05 17:34:01 +00:00
Add proper content-length for error and success responses
- All compliance issues with S3 API for Put,Get,List (Bucket,Object) respectively - Encodes and returns back proper HTTP headers
This commit is contained in:
parent
c8db3e1c3b
commit
92e4301414
7 changed files with 117 additions and 64 deletions
|
@ -18,6 +18,7 @@ package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
"github.com/minio-io/minio/pkg/iodine"
|
"github.com/minio-io/minio/pkg/iodine"
|
||||||
|
@ -88,12 +89,15 @@ func (server *minioAPI) listObjectsHandler(w http.ResponseWriter, req *http.Requ
|
||||||
switch err := iodine.ToError(err).(type) {
|
switch err := iodine.ToError(err).(type) {
|
||||||
case nil: // success
|
case nil: // success
|
||||||
{
|
{
|
||||||
|
// generate response
|
||||||
|
response := generateListObjectsResponse(bucket, objects, resources)
|
||||||
|
encodedSuccessResponse := encodeSuccessResponse(response, acceptsContentType)
|
||||||
// write headers
|
// write headers
|
||||||
setCommonHeaders(w, getContentTypeString(acceptsContentType))
|
setCommonHeaders(w, getContentTypeString(acceptsContentType))
|
||||||
|
// set content-length to the size of the body
|
||||||
|
w.Header().Set("Content-Length", strconv.Itoa(len(encodedSuccessResponse)))
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
// write body
|
// write body
|
||||||
response := generateObjectsListResult(bucket, objects, resources)
|
|
||||||
encodedSuccessResponse := encodeSuccessResponse(response, acceptsContentType)
|
|
||||||
w.Write(encodedSuccessResponse)
|
w.Write(encodedSuccessResponse)
|
||||||
}
|
}
|
||||||
case drivers.ObjectNotFound:
|
case drivers.ObjectNotFound:
|
||||||
|
@ -128,12 +132,15 @@ func (server *minioAPI) listBucketsHandler(w http.ResponseWriter, req *http.Requ
|
||||||
switch err := iodine.ToError(err).(type) {
|
switch err := iodine.ToError(err).(type) {
|
||||||
case nil:
|
case nil:
|
||||||
{
|
{
|
||||||
response := generateBucketsListResult(buckets)
|
// generate response
|
||||||
|
response := generateListBucketsResponse(buckets)
|
||||||
|
encodedSuccessResponse := encodeSuccessResponse(response, acceptsContentType)
|
||||||
// write headers
|
// write headers
|
||||||
setCommonHeaders(w, getContentTypeString(acceptsContentType))
|
setCommonHeaders(w, getContentTypeString(acceptsContentType))
|
||||||
|
// set content-length to the size of the body
|
||||||
|
w.Header().Set("Content-Length", strconv.Itoa(len(encodedSuccessResponse)))
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
// write response
|
// write response
|
||||||
encodedSuccessResponse := encodeSuccessResponse(response, acceptsContentType)
|
|
||||||
w.Write(encodedSuccessResponse)
|
w.Write(encodedSuccessResponse)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
@ -172,7 +179,9 @@ func (server *minioAPI) putBucketHandler(w http.ResponseWriter, req *http.Reques
|
||||||
switch iodine.ToError(err).(type) {
|
switch iodine.ToError(err).(type) {
|
||||||
case nil:
|
case nil:
|
||||||
{
|
{
|
||||||
writeSuccessResponse(w)
|
// Make sure to add Location information here only for bucket
|
||||||
|
w.Header().Set("Location", "/"+bucket)
|
||||||
|
writeSuccessResponse(w, acceptsContentType)
|
||||||
}
|
}
|
||||||
case drivers.TooManyBuckets:
|
case drivers.TooManyBuckets:
|
||||||
{
|
{
|
||||||
|
@ -217,7 +226,7 @@ func (server *minioAPI) putBucketACLHandler(w http.ResponseWriter, req *http.Req
|
||||||
switch iodine.ToError(err).(type) {
|
switch iodine.ToError(err).(type) {
|
||||||
case nil:
|
case nil:
|
||||||
{
|
{
|
||||||
writeSuccessResponse(w)
|
writeSuccessResponse(w, acceptsContentType)
|
||||||
}
|
}
|
||||||
case drivers.BucketNameInvalid:
|
case drivers.BucketNameInvalid:
|
||||||
{
|
{
|
||||||
|
@ -254,5 +263,5 @@ func (server *minioAPI) headBucketHandler(w http.ResponseWriter, req *http.Reque
|
||||||
}
|
}
|
||||||
|
|
||||||
// Always a success if isValidOp succeeds
|
// Always a success if isValidOp succeeds
|
||||||
writeSuccessResponse(w)
|
writeSuccessResponse(w, acceptsContentType)
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,8 +25,8 @@ const (
|
||||||
maxObjectList = 1000
|
maxObjectList = 1000
|
||||||
)
|
)
|
||||||
|
|
||||||
// ObjectListResponse format
|
// ListObjectsResponse - format for list objects response
|
||||||
type ObjectListResponse struct {
|
type ListObjectsResponse struct {
|
||||||
XMLName xml.Name `xml:"ListBucketResult" json:"-"`
|
XMLName xml.Name `xml:"ListBucketResult" json:"-"`
|
||||||
Name string
|
Name string
|
||||||
Prefix string
|
Prefix string
|
||||||
|
@ -38,8 +38,8 @@ type ObjectListResponse struct {
|
||||||
CommonPrefixes []*Prefix
|
CommonPrefixes []*Prefix
|
||||||
}
|
}
|
||||||
|
|
||||||
// BucketListResponse - bucket list response format
|
// ListBucketsResponse - format for list buckets response
|
||||||
type BucketListResponse struct {
|
type ListBucketsResponse struct {
|
||||||
XMLName xml.Name `xml:"ListAllMyBucketsResult" json:"-"`
|
XMLName xml.Name `xml:"ListAllMyBucketsResult" json:"-"`
|
||||||
Owner Owner
|
Owner Owner
|
||||||
Buckets struct {
|
Buckets struct {
|
||||||
|
@ -75,7 +75,7 @@ type Owner struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// List of not implemented bucket queries
|
// List of not implemented bucket queries
|
||||||
var unimplementedBucketResourceNames = map[string]bool{
|
var notimplementedBucketResourceNames = map[string]bool{
|
||||||
"policy": true,
|
"policy": true,
|
||||||
"cors": true,
|
"cors": true,
|
||||||
"lifecycle": true,
|
"lifecycle": true,
|
||||||
|
@ -91,7 +91,7 @@ var unimplementedBucketResourceNames = map[string]bool{
|
||||||
}
|
}
|
||||||
|
|
||||||
// List of not implemented object queries
|
// List of not implemented object queries
|
||||||
var unimplementedObjectResourceNames = map[string]bool{
|
var notimplementedObjectResourceNames = map[string]bool{
|
||||||
"uploadId": true,
|
"uploadId": true,
|
||||||
"torrent": true,
|
"torrent": true,
|
||||||
"uploads": true,
|
"uploads": true,
|
||||||
|
|
|
@ -162,7 +162,7 @@ func (h resourceHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
writeErrorResponse(w, r, NotAcceptable, acceptsContentType, r.URL.Path)
|
writeErrorResponse(w, r, NotAcceptable, acceptsContentType, r.URL.Path)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if ignoreUnImplementedObjectResources(r) || ignoreUnImplementedBucketResources(r) {
|
if ignoreNotImplementedObjectResources(r) || ignoreNotImplementedBucketResources(r) {
|
||||||
error := getErrorCode(NotImplemented)
|
error := getErrorCode(NotImplemented)
|
||||||
errorResponse := getErrorResponse(error, "")
|
errorResponse := getErrorResponse(error, "")
|
||||||
setCommonHeaders(w, getContentTypeString(acceptsContentType))
|
setCommonHeaders(w, getContentTypeString(acceptsContentType))
|
||||||
|
@ -175,22 +175,22 @@ func (h resourceHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
//// helpers
|
//// helpers
|
||||||
|
|
||||||
// Checks requests for unimplemented Bucket resources
|
// Checks requests for not implemented Bucket resources
|
||||||
func ignoreUnImplementedBucketResources(req *http.Request) bool {
|
func ignoreNotImplementedBucketResources(req *http.Request) bool {
|
||||||
q := req.URL.Query()
|
q := req.URL.Query()
|
||||||
for name := range q {
|
for name := range q {
|
||||||
if unimplementedBucketResourceNames[name] {
|
if notimplementedBucketResourceNames[name] {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks requests for unimplemented Object resources
|
// Checks requests for not implemented Object resources
|
||||||
func ignoreUnImplementedObjectResources(req *http.Request) bool {
|
func ignoreNotImplementedObjectResources(req *http.Request) bool {
|
||||||
q := req.URL.Query()
|
q := req.URL.Query()
|
||||||
for name := range q {
|
for name := range q {
|
||||||
if unimplementedObjectResourceNames[name] {
|
if notimplementedObjectResourceNames[name] {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -175,7 +175,26 @@ func (server *minioAPI) putObjectHandler(w http.ResponseWriter, req *http.Reques
|
||||||
switch err := iodine.ToError(err).(type) {
|
switch err := iodine.ToError(err).(type) {
|
||||||
case nil:
|
case nil:
|
||||||
{
|
{
|
||||||
writeSuccessResponse(w)
|
metadata, err := server.driver.GetObjectMetadata(bucket, object, "")
|
||||||
|
switch err := iodine.ToError(err).(type) {
|
||||||
|
case nil:
|
||||||
|
w.Header().Set("ETag", metadata.Md5)
|
||||||
|
writeSuccessResponse(w, acceptsContentType)
|
||||||
|
case drivers.ObjectNotFound:
|
||||||
|
{
|
||||||
|
writeErrorResponse(w, req, NoSuchKey, acceptsContentType, req.URL.Path)
|
||||||
|
}
|
||||||
|
case drivers.ObjectNameInvalid:
|
||||||
|
{
|
||||||
|
writeErrorResponse(w, req, NoSuchKey, acceptsContentType, req.URL.Path)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
log.Error.Println(iodine.New(err, nil))
|
||||||
|
writeErrorResponse(w, req, InternalError, acceptsContentType, req.URL.Path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
case drivers.ObjectExists:
|
case drivers.ObjectExists:
|
||||||
{
|
{
|
||||||
|
|
|
@ -19,6 +19,7 @@ package api
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"sort"
|
"sort"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
"github.com/minio-io/minio/pkg/storage/drivers"
|
"github.com/minio-io/minio/pkg/storage/drivers"
|
||||||
)
|
)
|
||||||
|
@ -34,9 +35,9 @@ const (
|
||||||
//
|
//
|
||||||
// output:
|
// output:
|
||||||
// populated struct that can be serialized to match xml and json api spec output
|
// populated struct that can be serialized to match xml and json api spec output
|
||||||
func generateBucketsListResult(buckets []drivers.BucketMetadata) BucketListResponse {
|
func generateListBucketsResponse(buckets []drivers.BucketMetadata) ListBucketsResponse {
|
||||||
var listbuckets []*Bucket
|
var listbuckets []*Bucket
|
||||||
var data = BucketListResponse{}
|
var data = ListBucketsResponse{}
|
||||||
var owner = Owner{}
|
var owner = Owner{}
|
||||||
|
|
||||||
owner.ID = "minio"
|
owner.ID = "minio"
|
||||||
|
@ -70,11 +71,11 @@ func (b itemKey) Less(i, j int) bool { return b[i].Key < b[j].Key }
|
||||||
//
|
//
|
||||||
// output:
|
// output:
|
||||||
// populated struct that can be serialized to match xml and json api spec output
|
// populated struct that can be serialized to match xml and json api spec output
|
||||||
func generateObjectsListResult(bucket string, objects []drivers.ObjectMetadata, bucketResources drivers.BucketResourcesMetadata) ObjectListResponse {
|
func generateListObjectsResponse(bucket string, objects []drivers.ObjectMetadata, bucketResources drivers.BucketResourcesMetadata) ListObjectsResponse {
|
||||||
var contents []*Item
|
var contents []*Item
|
||||||
var prefixes []*Prefix
|
var prefixes []*Prefix
|
||||||
var owner = Owner{}
|
var owner = Owner{}
|
||||||
var data = ObjectListResponse{}
|
var data = ListObjectsResponse{}
|
||||||
|
|
||||||
owner.ID = "minio"
|
owner.ID = "minio"
|
||||||
owner.DisplayName = "minio"
|
owner.DisplayName = "minio"
|
||||||
|
@ -110,20 +111,23 @@ func generateObjectsListResult(bucket string, objects []drivers.ObjectMetadata,
|
||||||
}
|
}
|
||||||
|
|
||||||
// writeSuccessResponse - write success headers
|
// writeSuccessResponse - write success headers
|
||||||
func writeSuccessResponse(w http.ResponseWriter) {
|
func writeSuccessResponse(w http.ResponseWriter, acceptsContentType contentType) {
|
||||||
w.Header().Set("Server", "Minio")
|
setCommonHeaders(w, getContentTypeString(acceptsContentType))
|
||||||
w.Header().Set("Connection", "close")
|
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
}
|
}
|
||||||
|
|
||||||
// writeErrorRespone - write error headers
|
// writeErrorRespone - write error headers
|
||||||
func writeErrorResponse(w http.ResponseWriter, req *http.Request, errorType int, acceptsContentType contentType, resource string) {
|
func writeErrorResponse(w http.ResponseWriter, req *http.Request, errorType int, acceptsContentType contentType, resource string) {
|
||||||
error := getErrorCode(errorType)
|
error := getErrorCode(errorType)
|
||||||
|
// generate error response
|
||||||
errorResponse := getErrorResponse(error, resource)
|
errorResponse := getErrorResponse(error, resource)
|
||||||
// set headers
|
encodedErrorResponse := encodeErrorResponse(errorResponse, acceptsContentType)
|
||||||
|
// set common headers
|
||||||
setCommonHeaders(w, getContentTypeString(acceptsContentType))
|
setCommonHeaders(w, getContentTypeString(acceptsContentType))
|
||||||
|
// set content-length to size of error response
|
||||||
|
w.Header().Set("Content-Length", strconv.Itoa(len(encodedErrorResponse)))
|
||||||
|
// set headers
|
||||||
w.WriteHeader(error.HTTPStatusCode)
|
w.WriteHeader(error.HTTPStatusCode)
|
||||||
// write body
|
// write body
|
||||||
encodedErrorResponse := encodeErrorResponse(errorResponse, acceptsContentType)
|
|
||||||
w.Write(encodedErrorResponse)
|
w.Write(encodedErrorResponse)
|
||||||
}
|
}
|
||||||
|
|
|
@ -168,6 +168,7 @@ func (s *MySuite) TestEmptyObject(c *C) {
|
||||||
}
|
}
|
||||||
typedDriver.On("CreateBucket", "bucket", "private").Return(nil).Once()
|
typedDriver.On("CreateBucket", "bucket", "private").Return(nil).Once()
|
||||||
typedDriver.On("CreateObject", "bucket", "object", "", "", mock.Anything).Return(nil).Once()
|
typedDriver.On("CreateObject", "bucket", "object", "", "", mock.Anything).Return(nil).Once()
|
||||||
|
typedDriver.On("GetObjectMetadata", "bucket", "object", "").Return(metadata, nil).Once()
|
||||||
typedDriver.On("GetBucketMetadata", "bucket").Return(drivers.BucketMetadata{}, nil).Twice()
|
typedDriver.On("GetBucketMetadata", "bucket").Return(drivers.BucketMetadata{}, nil).Twice()
|
||||||
typedDriver.On("GetObjectMetadata", "bucket", "object", "").Return(metadata, nil).Once()
|
typedDriver.On("GetObjectMetadata", "bucket", "object", "").Return(metadata, nil).Once()
|
||||||
typedDriver.On("GetObject", mock.Anything, "bucket", "object").Return(int64(0), nil).Once()
|
typedDriver.On("GetObject", mock.Anything, "bucket", "object").Return(int64(0), nil).Once()
|
||||||
|
@ -179,6 +180,7 @@ func (s *MySuite) TestEmptyObject(c *C) {
|
||||||
buffer := bytes.NewBufferString("")
|
buffer := bytes.NewBufferString("")
|
||||||
driver.CreateBucket("bucket", "private")
|
driver.CreateBucket("bucket", "private")
|
||||||
driver.CreateObject("bucket", "object", "", "", buffer)
|
driver.CreateObject("bucket", "object", "", "", buffer)
|
||||||
|
driver.GetObjectMetadata("bucket", "object", "")
|
||||||
|
|
||||||
request, err := http.NewRequest("GET", testServer.URL+"/bucket/object", nil)
|
request, err := http.NewRequest("GET", testServer.URL+"/bucket/object", nil)
|
||||||
c.Assert(err, IsNil)
|
c.Assert(err, IsNil)
|
||||||
|
@ -250,6 +252,7 @@ func (s *MySuite) TestObject(c *C) {
|
||||||
}
|
}
|
||||||
typedDriver.On("CreateBucket", "bucket", "private").Return(nil).Once()
|
typedDriver.On("CreateBucket", "bucket", "private").Return(nil).Once()
|
||||||
typedDriver.On("CreateObject", "bucket", "object", "", "", mock.Anything).Return(nil).Once()
|
typedDriver.On("CreateObject", "bucket", "object", "", "", mock.Anything).Return(nil).Once()
|
||||||
|
typedDriver.On("GetObjectMetadata", "bucket", "object", "").Return(metadata, nil).Twice()
|
||||||
typedDriver.On("GetBucketMetadata", "bucket").Return(drivers.BucketMetadata{}, nil).Twice()
|
typedDriver.On("GetBucketMetadata", "bucket").Return(drivers.BucketMetadata{}, nil).Twice()
|
||||||
typedDriver.On("GetObjectMetadata", "bucket", "object", "").Return(metadata, nil).Twice()
|
typedDriver.On("GetObjectMetadata", "bucket", "object", "").Return(metadata, nil).Twice()
|
||||||
typedDriver.SetGetObjectWriter("bucket", "object", []byte("hello world"))
|
typedDriver.SetGetObjectWriter("bucket", "object", []byte("hello world"))
|
||||||
|
@ -262,6 +265,7 @@ func (s *MySuite) TestObject(c *C) {
|
||||||
buffer := bytes.NewBufferString("hello world")
|
buffer := bytes.NewBufferString("hello world")
|
||||||
driver.CreateBucket("bucket", "private")
|
driver.CreateBucket("bucket", "private")
|
||||||
driver.CreateObject("bucket", "object", "", "", buffer)
|
driver.CreateObject("bucket", "object", "", "", buffer)
|
||||||
|
driver.GetObjectMetadata("bucket", "object", "")
|
||||||
|
|
||||||
request, err := http.NewRequest("GET", testServer.URL+"/bucket/object", nil)
|
request, err := http.NewRequest("GET", testServer.URL+"/bucket/object", nil)
|
||||||
c.Assert(err, IsNil)
|
c.Assert(err, IsNil)
|
||||||
|
@ -325,11 +329,17 @@ func (s *MySuite) TestMultipleObjects(c *C) {
|
||||||
typedDriver.On("CreateBucket", "bucket", "private").Return(nil).Once()
|
typedDriver.On("CreateBucket", "bucket", "private").Return(nil).Once()
|
||||||
driver.CreateBucket("bucket", "private")
|
driver.CreateBucket("bucket", "private")
|
||||||
typedDriver.On("CreateObject", "bucket", "object1", "", "", mock.Anything).Return(nil).Once()
|
typedDriver.On("CreateObject", "bucket", "object1", "", "", mock.Anything).Return(nil).Once()
|
||||||
|
typedDriver.On("GetObjectMetadata", "bucket", "object1", "").Return(metadata1, nil).Once()
|
||||||
driver.CreateObject("bucket", "object1", "", "", buffer1)
|
driver.CreateObject("bucket", "object1", "", "", buffer1)
|
||||||
|
driver.GetObjectMetadata("bucket", "object1", "")
|
||||||
typedDriver.On("CreateObject", "bucket", "object2", "", "", mock.Anything).Return(nil).Once()
|
typedDriver.On("CreateObject", "bucket", "object2", "", "", mock.Anything).Return(nil).Once()
|
||||||
|
typedDriver.On("GetObjectMetadata", "bucket", "object2", "").Return(metadata2, nil).Once()
|
||||||
driver.CreateObject("bucket", "object2", "", "", buffer2)
|
driver.CreateObject("bucket", "object2", "", "", buffer2)
|
||||||
|
driver.GetObjectMetadata("bucket", "object2", "")
|
||||||
typedDriver.On("CreateObject", "bucket", "object3", "", "", mock.Anything).Return(nil).Once()
|
typedDriver.On("CreateObject", "bucket", "object3", "", "", mock.Anything).Return(nil).Once()
|
||||||
|
typedDriver.On("GetObjectMetadata", "bucket", "object3", "").Return(metadata3, nil).Once()
|
||||||
driver.CreateObject("bucket", "object3", "", "", buffer3)
|
driver.CreateObject("bucket", "object3", "", "", buffer3)
|
||||||
|
driver.GetObjectMetadata("bucket", "object3", "")
|
||||||
|
|
||||||
// test non-existant object
|
// test non-existant object
|
||||||
typedDriver.On("GetBucketMetadata", "bucket").Return(drivers.BucketMetadata{}, nil).Once()
|
typedDriver.On("GetBucketMetadata", "bucket").Return(drivers.BucketMetadata{}, nil).Once()
|
||||||
|
@ -494,11 +504,6 @@ func (s *MySuite) TestHeader(c *C) {
|
||||||
|
|
||||||
verifyError(c, response, "NoSuchKey", "The specified key does not exist.", http.StatusNotFound)
|
verifyError(c, response, "NoSuchKey", "The specified key does not exist.", http.StatusNotFound)
|
||||||
|
|
||||||
buffer := bytes.NewBufferString("hello world")
|
|
||||||
typedDriver.On("GetBucketMetadata", "foo").Return(bucketMetadata, nil).Once()
|
|
||||||
typedDriver.On("CreateObject", "bucket", "object", "", "", mock.Anything).Return(nil).Once()
|
|
||||||
driver.CreateObject("bucket", "object", "", "", buffer)
|
|
||||||
|
|
||||||
objectMetadata := drivers.ObjectMetadata{
|
objectMetadata := drivers.ObjectMetadata{
|
||||||
Bucket: "bucket",
|
Bucket: "bucket",
|
||||||
Key: "object",
|
Key: "object",
|
||||||
|
@ -508,6 +513,13 @@ func (s *MySuite) TestHeader(c *C) {
|
||||||
Size: 11,
|
Size: 11,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buffer := bytes.NewBufferString("hello world")
|
||||||
|
typedDriver.On("GetBucketMetadata", "foo").Return(bucketMetadata, nil).Once()
|
||||||
|
typedDriver.On("CreateObject", "bucket", "object", "", "", mock.Anything).Return(nil).Once()
|
||||||
|
typedDriver.On("GetObjectMetadata", "bucket", "object", "").Return(objectMetadata, nil).Once()
|
||||||
|
driver.CreateObject("bucket", "object", "", "", buffer)
|
||||||
|
driver.GetObjectMetadata("bucket", "object", "")
|
||||||
|
|
||||||
typedDriver.On("GetBucketMetadata", "bucket").Return(bucketMetadata, nil).Once()
|
typedDriver.On("GetBucketMetadata", "bucket").Return(bucketMetadata, nil).Once()
|
||||||
typedDriver.On("GetObjectMetadata", "bucket", "object", "").Return(objectMetadata, nil).Once()
|
typedDriver.On("GetObjectMetadata", "bucket", "object", "").Return(objectMetadata, nil).Once()
|
||||||
typedDriver.SetGetObjectWriter("", "", []byte("hello world"))
|
typedDriver.SetGetObjectWriter("", "", []byte("hello world"))
|
||||||
|
@ -608,15 +620,6 @@ func (s *MySuite) TestPutObject(c *C) {
|
||||||
c.Assert(err, IsNil)
|
c.Assert(err, IsNil)
|
||||||
c.Assert(response.StatusCode, Equals, http.StatusOK)
|
c.Assert(response.StatusCode, Equals, http.StatusOK)
|
||||||
|
|
||||||
typedDriver.On("CreateObject", "bucket", "two", "", "", mock.Anything).Return(nil).Once()
|
|
||||||
request, err = http.NewRequest("PUT", testServer.URL+"/bucket/two", bytes.NewBufferString("hello world"))
|
|
||||||
c.Assert(err, IsNil)
|
|
||||||
setAuthHeader(request)
|
|
||||||
|
|
||||||
response, err = client.Do(request)
|
|
||||||
c.Assert(err, IsNil)
|
|
||||||
c.Assert(response.StatusCode, Equals, http.StatusOK)
|
|
||||||
|
|
||||||
twoMetadata := drivers.ObjectMetadata{
|
twoMetadata := drivers.ObjectMetadata{
|
||||||
Bucket: "bucket",
|
Bucket: "bucket",
|
||||||
Key: "two",
|
Key: "two",
|
||||||
|
@ -626,6 +629,16 @@ func (s *MySuite) TestPutObject(c *C) {
|
||||||
Size: 11,
|
Size: 11,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedDriver.On("CreateObject", "bucket", "two", "", "", mock.Anything).Return(nil).Once()
|
||||||
|
typedDriver.On("GetObjectMetadata", "bucket", "two", "").Return(twoMetadata, nil).Once()
|
||||||
|
request, err = http.NewRequest("PUT", testServer.URL+"/bucket/two", bytes.NewBufferString("hello world"))
|
||||||
|
c.Assert(err, IsNil)
|
||||||
|
setAuthHeader(request)
|
||||||
|
|
||||||
|
response, err = client.Do(request)
|
||||||
|
c.Assert(err, IsNil)
|
||||||
|
c.Assert(response.StatusCode, Equals, http.StatusOK)
|
||||||
|
|
||||||
date2 := time.Now()
|
date2 := time.Now()
|
||||||
|
|
||||||
resources.Maxkeys = 1000
|
resources.Maxkeys = 1000
|
||||||
|
@ -731,8 +744,8 @@ func (s *MySuite) TestListBuckets(c *C) {
|
||||||
c.Assert(listResponse.Buckets.Bucket[1].Name, Equals, "foo")
|
c.Assert(listResponse.Buckets.Bucket[1].Name, Equals, "foo")
|
||||||
}
|
}
|
||||||
|
|
||||||
func readListBucket(reader io.Reader) (BucketListResponse, error) {
|
func readListBucket(reader io.Reader) (ListBucketsResponse, error) {
|
||||||
var results BucketListResponse
|
var results ListBucketsResponse
|
||||||
decoder := xml.NewDecoder(reader)
|
decoder := xml.NewDecoder(reader)
|
||||||
err := decoder.Decode(&results)
|
err := decoder.Decode(&results)
|
||||||
return results, err
|
return results, err
|
||||||
|
@ -893,8 +906,19 @@ func (s *MySuite) TestContentTypePersists(c *C) {
|
||||||
Created: time.Now(),
|
Created: time.Now(),
|
||||||
ACL: drivers.BucketACL("private"),
|
ACL: drivers.BucketACL("private"),
|
||||||
}
|
}
|
||||||
|
// test head
|
||||||
|
oneMetadata := drivers.ObjectMetadata{
|
||||||
|
Bucket: "bucket",
|
||||||
|
Key: "one",
|
||||||
|
ContentType: "application/octet-stream",
|
||||||
|
Created: time.Now(),
|
||||||
|
Md5: "d41d8cd98f00b204e9800998ecf8427e",
|
||||||
|
Size: 0,
|
||||||
|
}
|
||||||
|
|
||||||
typedDriver.On("GetBucketMetadata", "bucket").Return(metadata, nil).Once()
|
typedDriver.On("GetBucketMetadata", "bucket").Return(metadata, nil).Once()
|
||||||
typedDriver.On("CreateObject", "bucket", "one", "", "", mock.Anything).Return(nil).Once()
|
typedDriver.On("CreateObject", "bucket", "one", "", "", mock.Anything).Return(nil).Once()
|
||||||
|
typedDriver.On("GetObjectMetadata", "bucket", "one", "").Return(oneMetadata, nil).Once()
|
||||||
request, err := http.NewRequest("PUT", testServer.URL+"/bucket/one", bytes.NewBufferString("hello world"))
|
request, err := http.NewRequest("PUT", testServer.URL+"/bucket/one", bytes.NewBufferString("hello world"))
|
||||||
delete(request.Header, "Content-Type")
|
delete(request.Header, "Content-Type")
|
||||||
c.Assert(err, IsNil)
|
c.Assert(err, IsNil)
|
||||||
|
@ -905,15 +929,6 @@ func (s *MySuite) TestContentTypePersists(c *C) {
|
||||||
c.Assert(err, IsNil)
|
c.Assert(err, IsNil)
|
||||||
c.Assert(response.StatusCode, Equals, http.StatusOK)
|
c.Assert(response.StatusCode, Equals, http.StatusOK)
|
||||||
|
|
||||||
// test head
|
|
||||||
oneMetadata := drivers.ObjectMetadata{
|
|
||||||
Bucket: "bucket",
|
|
||||||
Key: "one",
|
|
||||||
ContentType: "application/octet-stream",
|
|
||||||
Created: time.Now(),
|
|
||||||
Md5: "d41d8cd98f00b204e9800998ecf8427e",
|
|
||||||
Size: 0,
|
|
||||||
}
|
|
||||||
typedDriver.On("GetBucketMetadata", "bucket").Return(drivers.BucketMetadata{}, nil).Once()
|
typedDriver.On("GetBucketMetadata", "bucket").Return(drivers.BucketMetadata{}, nil).Once()
|
||||||
typedDriver.On("GetObjectMetadata", "bucket", "one", "").Return(oneMetadata, nil).Once()
|
typedDriver.On("GetObjectMetadata", "bucket", "one", "").Return(oneMetadata, nil).Once()
|
||||||
request, err = http.NewRequest("HEAD", testServer.URL+"/bucket/one", nil)
|
request, err = http.NewRequest("HEAD", testServer.URL+"/bucket/one", nil)
|
||||||
|
@ -939,8 +954,19 @@ func (s *MySuite) TestContentTypePersists(c *C) {
|
||||||
c.Assert(response.StatusCode, Equals, http.StatusOK)
|
c.Assert(response.StatusCode, Equals, http.StatusOK)
|
||||||
c.Assert(response.Header.Get("Content-Type"), Equals, "application/octet-stream")
|
c.Assert(response.Header.Get("Content-Type"), Equals, "application/octet-stream")
|
||||||
|
|
||||||
|
twoMetadata := drivers.ObjectMetadata{
|
||||||
|
Bucket: "bucket",
|
||||||
|
Key: "one",
|
||||||
|
ContentType: "application/octet-stream",
|
||||||
|
Created: time.Now(),
|
||||||
|
// Fix MD5
|
||||||
|
Md5: "d41d8cd98f00b204e9800998ecf8427e",
|
||||||
|
Size: 0,
|
||||||
|
}
|
||||||
|
|
||||||
typedDriver.On("GetBucketMetadata", "bucket").Return(metadata, nil).Once()
|
typedDriver.On("GetBucketMetadata", "bucket").Return(metadata, nil).Once()
|
||||||
typedDriver.On("CreateObject", "bucket", "two", "", "", mock.Anything).Return(nil).Once()
|
typedDriver.On("CreateObject", "bucket", "two", "", "", mock.Anything).Return(nil).Once()
|
||||||
|
typedDriver.On("GetObjectMetadata", "bucket", "two", "").Return(twoMetadata, nil).Once()
|
||||||
request, err = http.NewRequest("PUT", testServer.URL+"/bucket/two", bytes.NewBufferString("hello world"))
|
request, err = http.NewRequest("PUT", testServer.URL+"/bucket/two", bytes.NewBufferString("hello world"))
|
||||||
delete(request.Header, "Content-Type")
|
delete(request.Header, "Content-Type")
|
||||||
request.Header.Add("Content-Type", "application/json")
|
request.Header.Add("Content-Type", "application/json")
|
||||||
|
@ -951,15 +977,6 @@ func (s *MySuite) TestContentTypePersists(c *C) {
|
||||||
c.Assert(err, IsNil)
|
c.Assert(err, IsNil)
|
||||||
c.Assert(response.StatusCode, Equals, http.StatusOK)
|
c.Assert(response.StatusCode, Equals, http.StatusOK)
|
||||||
|
|
||||||
twoMetadata := drivers.ObjectMetadata{
|
|
||||||
Bucket: "bucket",
|
|
||||||
Key: "one",
|
|
||||||
ContentType: "application/octet-stream",
|
|
||||||
Created: time.Now(),
|
|
||||||
// Fix MD5
|
|
||||||
Md5: "d41d8cd98f00b204e9800998ecf8427e",
|
|
||||||
Size: 0,
|
|
||||||
}
|
|
||||||
typedDriver.On("GetBucketMetadata", "bucket").Return(metadata, nil).Once()
|
typedDriver.On("GetBucketMetadata", "bucket").Return(metadata, nil).Once()
|
||||||
typedDriver.On("GetObjectMetadata", "bucket", "two", "").Return(twoMetadata, nil).Once()
|
typedDriver.On("GetObjectMetadata", "bucket", "two", "").Return(twoMetadata, nil).Once()
|
||||||
request, err = http.NewRequest("HEAD", testServer.URL+"/bucket/two", nil)
|
request, err = http.NewRequest("HEAD", testServer.URL+"/bucket/two", nil)
|
||||||
|
@ -1008,10 +1025,12 @@ func (s *MySuite) TestPartialContent(c *C) {
|
||||||
|
|
||||||
typedDriver.On("CreateBucket", "foo", "private").Return(nil).Once()
|
typedDriver.On("CreateBucket", "foo", "private").Return(nil).Once()
|
||||||
typedDriver.On("CreateObject", "foo", "bar", "", "", mock.Anything).Return(nil).Once()
|
typedDriver.On("CreateObject", "foo", "bar", "", "", mock.Anything).Return(nil).Once()
|
||||||
|
typedDriver.On("GetObjectMetadata", "foo", "bar", "").Return(metadata, nil).Once()
|
||||||
err := driver.CreateBucket("foo", "private")
|
err := driver.CreateBucket("foo", "private")
|
||||||
c.Assert(err, IsNil)
|
c.Assert(err, IsNil)
|
||||||
|
|
||||||
driver.CreateObject("foo", "bar", "", "", bytes.NewBufferString("hello world"))
|
driver.CreateObject("foo", "bar", "", "", bytes.NewBufferString("hello world"))
|
||||||
|
driver.GetObjectMetadata("foo", "bar", "")
|
||||||
|
|
||||||
// prepare for GET on range request
|
// prepare for GET on range request
|
||||||
typedDriver.SetGetObjectWriter("foo", "bar", []byte("hello world"))
|
typedDriver.SetGetObjectWriter("foo", "bar", []byte("hello world"))
|
||||||
|
|
|
@ -40,6 +40,8 @@ func setCommonHeaders(w http.ResponseWriter, acceptsType string) {
|
||||||
w.Header().Set("Accept-Ranges", "bytes")
|
w.Header().Set("Accept-Ranges", "bytes")
|
||||||
w.Header().Set("Content-Type", acceptsType)
|
w.Header().Set("Content-Type", acceptsType)
|
||||||
w.Header().Set("Connection", "close")
|
w.Header().Set("Connection", "close")
|
||||||
|
// should be set to '0' by default
|
||||||
|
w.Header().Set("Content-Length", "0")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write error response headers
|
// Write error response headers
|
||||||
|
|
Loading…
Reference in a new issue