diff --git a/pkg/api/api_bucket_handlers.go b/pkg/api/api_bucket_handlers.go index 341648519..61b6ee423 100644 --- a/pkg/api/api_bucket_handlers.go +++ b/pkg/api/api_bucket_handlers.go @@ -36,6 +36,14 @@ func (server *minioAPI) listObjectsHandler(w http.ResponseWriter, req *http.Requ resources := getBucketResources(req.URL.Query()) if resources.Policy == true { + // TODO + // ---- + // This is handled here instead of router, is only because semantically + // resource queries are not treated differently by Gorilla mux + // + // In-fact a request coming in as /bucket/?policy={} and /bucket/object are + // treated similarly. A proper fix would be to remove this comment and + // find a right regex pattern for individual requests server.getBucketPolicyHandler(w, req) return } diff --git a/pkg/api/api_object_handlers.go b/pkg/api/api_object_handlers.go index 493e590e0..06a08e10d 100644 --- a/pkg/api/api_object_handlers.go +++ b/pkg/api/api_object_handlers.go @@ -51,13 +51,13 @@ func (server *minioAPI) getObjectHandler(w http.ResponseWriter, req *http.Reques setObjectHeaders(w, metadata) if _, err := server.driver.GetObject(w, bucket, object); err != nil { // unable to write headers, we've already printed data. Just close the connection. + log.Error.Println(err) } } case false: { metadata.Size = httpRange.length setRangeObjectHeaders(w, metadata, httpRange) - // contentRangeValue := "bytes " + strconv.FormatInt(httpRange.start, 10) + "-" + strconv.FormatInt(httpRange.length, 10) + "/" + strconv.FormatInt(httpRange.size, 10) w.WriteHeader(http.StatusPartialContent) _, err := server.driver.GetPartialObject(w, bucket, object, httpRange.start, httpRange.length) if err != nil { @@ -147,8 +147,14 @@ func (server *minioAPI) putObjectHandler(w http.ResponseWriter, req *http.Reques resources := getBucketResources(req.URL.Query()) if resources.Policy == true && object == "" { - // TODO figure out if we can hand this off to router instead of embedding here. - // hand off request to pubBucketPolicyHandler + // TODO + // ---- + // This is handled here instead of router, is only because semantically + // resource queries are not treated differently by Gorilla mux + // + // In-fact a request coming in as /bucket/?policy={} and /bucket/object are + // treated similarly. A proper fix would be to remove this comment and + // find a right regex pattern for individual requests server.putBucketPolicyHandler(w, req) return } diff --git a/pkg/api/api_response.go b/pkg/api/api_response.go index d70388d51..17beae48c 100644 --- a/pkg/api/api_response.go +++ b/pkg/api/api_response.go @@ -54,15 +54,11 @@ func generateBucketsListResult(buckets []drivers.BucketMetadata) BucketListRespo return data } +// itemKey type itemKey []*Item -// Len -func (b itemKey) Len() int { return len(b) } - -// Swap -func (b itemKey) Swap(i, j int) { b[i], b[j] = b[j], b[i] } - -// Less +func (b itemKey) Len() int { return len(b) } +func (b itemKey) Swap(i, j int) { b[i], b[j] = b[j], b[i] } func (b itemKey) Less(i, j int) bool { return b[i].Key < b[j].Key } // takes a set of objects and prepares the objects for serialization diff --git a/pkg/api/api_test.go b/pkg/api/api_test.go index 16453c546..eb096570d 100644 --- a/pkg/api/api_test.go +++ b/pkg/api/api_test.go @@ -31,6 +31,7 @@ import ( "testing" "time" + "github.com/clbanning/mxj" "github.com/minio-io/minio/pkg/api" "github.com/minio-io/minio/pkg/drivers" "github.com/minio-io/minio/pkg/drivers/donut" @@ -121,6 +122,34 @@ func (s *MySuite) TearDownTest(c *C) { s.Root = "" } +/* **** SAMPLE ERROR RESPONSE **** + + + AccessDenied + Access Denied + /mybucket/myphoto.jpg + F19772218238A85A + GuWkjyviSiGHizehqpmsD1ndz5NClSP19DOT+s2mv7gXGQ8/X1lhbDGiIJEXpGFD + +*/ + +type responseMap struct { + res *http.Response // response headers + resMsg mxj.Map // Keys: Code, Message, Resource, RequestId, HostId +} + +// parseResponse returns a new initialized S3.Error structure +func parseResponse(res *http.Response) (*responseMap, error) { + var err error + resp := responseMap{} + resp.res = res + resp.resMsg, err = mxj.NewMapXmlReader(res.Body) + if err != nil { + return nil, err + } + return &resp, nil +} + func (s *MySuite) TestNonExistantObject(c *C) { driver := s.Driver s.MockDriver.On("GetObjectMetadata", "bucket", "object", "").Return(drivers.ObjectMetadata{}, drivers.BucketNotFound{Bucket: "bucket"}).Once() @@ -130,7 +159,6 @@ func (s *MySuite) TestNonExistantObject(c *C) { response, err := http.Get(testServer.URL + "/bucket/object") c.Assert(err, IsNil) - c.Log(response.StatusCode) c.Assert(response.StatusCode, Equals, http.StatusNotFound) } @@ -217,9 +245,8 @@ func (s *MySuite) TestMultipleObjects(c *C) { Key: "object1", ContentType: "application/octet-stream", Created: time.Now(), - // TODO correct md5 - Md5: "5eb63bbbe01eeed093cb22bb8f5acdc3", - Size: 9, + Md5: "5eb63bbbe01eeed093cb22bb8f5acdc3", // TODO correct md5 + Size: 9, } metadata2 := drivers.ObjectMetadata{ Bucket: "bucket", @@ -258,8 +285,12 @@ func (s *MySuite) TestMultipleObjects(c *C) { typedDriver.On("GetObjectMetadata", "bucket", "object", "").Return(drivers.ObjectMetadata{}, drivers.ObjectNotFound{}).Once() response, err := http.Get(testServer.URL + "/bucket/object") c.Assert(err, IsNil) - c.Assert(response.StatusCode, Equals, http.StatusNotFound) - // TODO Test Headers + responseMap, err := parseResponse(response) + c.Assert(err, IsNil) + c.Assert(responseMap.res.StatusCode, Equals, http.StatusNotFound) + values, err := responseMap.resMsg.ValuesForKey("Code") + c.Assert(err, IsNil) + c.Assert(values[0], Equals, "NoSuchKey") //// test object 1 @@ -341,6 +372,7 @@ func (s *MySuite) TestNotImplemented(c *C) { response, err := http.Get(testServer.URL + "/bucket/object?acl") c.Assert(err, IsNil) c.Assert(response.StatusCode, Equals, http.StatusNotImplemented) + } func (s *MySuite) TestHeader(c *C) { @@ -354,7 +386,12 @@ func (s *MySuite) TestHeader(c *C) { typedDriver.On("GetObjectMetadata", "bucket", "object", "").Return(drivers.ObjectMetadata{}, drivers.ObjectNotFound{}).Once() response, err := http.Get(testServer.URL + "/bucket/object") c.Assert(err, IsNil) - c.Assert(response.StatusCode, Equals, http.StatusNotFound) + responseMap, err := parseResponse(response) + c.Assert(err, IsNil) + c.Assert(responseMap.res.StatusCode, Equals, http.StatusNotFound) + values, err := responseMap.resMsg.ValuesForKey("Code") + c.Assert(err, IsNil) + c.Assert(values[0], Equals, "NoSuchKey") buffer := bytes.NewBufferString("hello world") typedDriver.On("CreateBucket", "bucket").Return(nil).Once() @@ -367,9 +404,8 @@ func (s *MySuite) TestHeader(c *C) { Key: "object", ContentType: "application/octet-stream", Created: time.Now(), - // TODO correct md5 - Md5: "5eb63bbbe01eeed093cb22bb8f5acdc3", - Size: 11, + Md5: "5eb63bbbe01eeed093cb22bb8f5acdc3", // TODO correct md5 + Size: 11, } typedDriver.On("GetObjectMetadata", "bucket", "object", "").Return(objectMetadata, nil).Once() @@ -731,9 +767,8 @@ func (s *MySuite) TestPartialContent(c *C) { Key: "bar", ContentType: "application/octet-stream", Created: time.Now(), - // TODO Determine if md5 of range or full object needed - Md5: "e81c4e4f2b7b93b481e13a8553c2ae1b", - Size: 11, + Md5: "e81c4e4f2b7b93b481e13a8553c2ae1b", // TODO Determine if md5 of range or full object needed + Size: 11, } typedDriver.On("CreateBucket", "foo").Return(nil).Once() diff --git a/pkg/drivers/file/file_object.go b/pkg/drivers/file/file_object.go index 3adfc4014..02537b51e 100644 --- a/pkg/drivers/file/file_object.go +++ b/pkg/drivers/file/file_object.go @@ -88,6 +88,11 @@ func (file *fileDriver) GetObject(w io.Writer, bucket string, object string) (in return 0, drivers.BucketNameInvalid{Bucket: bucket} } + // check bucket exists + if _, err := os.Stat(path.Join(file.root, bucket)); os.IsNotExist(err) { + return 0, drivers.BucketNotFound{Bucket: bucket} + } + // validate object if drivers.IsValidObject(object) == false { return 0, drivers.ObjectNameInvalid{Bucket: bucket, Object: object}