parent
7d8c34e055
commit
eeae64935e
@ -0,0 +1,235 @@ |
||||
package minioapi |
||||
|
||||
import ( |
||||
"encoding/json" |
||||
"log" |
||||
"net/http" |
||||
|
||||
"github.com/gorilla/mux" |
||||
mstorage "github.com/minio-io/minio/pkg/storage" |
||||
"github.com/minio-io/minio/pkg/utils/policy" |
||||
) |
||||
|
||||
func (server *minioApi) putBucketPolicyHandler(w http.ResponseWriter, req *http.Request) { |
||||
vars := mux.Vars(req) |
||||
bucket := vars["bucket"] |
||||
acceptsContentType := getContentType(req) |
||||
|
||||
policy, ok := policy.Parsepolicy(req.Body) |
||||
if ok == false { |
||||
error := errorCodeError(InvalidPolicyDocument) |
||||
errorResponse := getErrorResponse(error, bucket) |
||||
w.WriteHeader(error.HttpStatusCode) |
||||
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) |
||||
return |
||||
} |
||||
|
||||
err := server.storage.StoreBucketPolicy(bucket, policy) |
||||
switch err := err.(type) { |
||||
case nil: |
||||
{ |
||||
w.WriteHeader(http.StatusNoContent) |
||||
writeCommonHeaders(w, getContentString(acceptsContentType)) |
||||
w.Header().Set("Connection", "keep-alive") |
||||
} |
||||
case mstorage.BucketNameInvalid: |
||||
{ |
||||
error := errorCodeError(InvalidBucketName) |
||||
errorResponse := getErrorResponse(error, bucket) |
||||
w.WriteHeader(error.HttpStatusCode) |
||||
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) |
||||
} |
||||
case mstorage.BucketNotFound: |
||||
{ |
||||
error := errorCodeError(NoSuchBucket) |
||||
errorResponse := getErrorResponse(error, bucket) |
||||
w.WriteHeader(error.HttpStatusCode) |
||||
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) |
||||
} |
||||
case mstorage.BackendCorrupted: |
||||
case mstorage.ImplementationError: |
||||
{ |
||||
log.Println(err) |
||||
error := errorCodeError(InternalError) |
||||
errorResponse := getErrorResponse(error, bucket) |
||||
w.WriteHeader(error.HttpStatusCode) |
||||
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) |
||||
} |
||||
} |
||||
} |
||||
|
||||
func (server *minioApi) getBucketPolicyHandler(w http.ResponseWriter, req *http.Request) { |
||||
vars := mux.Vars(req) |
||||
bucket := vars["bucket"] |
||||
acceptsContentType := getContentType(req) |
||||
|
||||
p, err := server.storage.GetBucketPolicy(bucket) |
||||
switch err := err.(type) { |
||||
case nil: |
||||
{ |
||||
responsePolicy, ret := json.Marshal(p) |
||||
if ret != nil { |
||||
error := errorCodeError(InternalError) |
||||
errorResponse := getErrorResponse(error, bucket) |
||||
w.WriteHeader(error.HttpStatusCode) |
||||
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) |
||||
} |
||||
writeCommonHeaders(w, getContentString(acceptsContentType)) |
||||
w.Header().Set("Connection", "keep-alive") |
||||
w.Write(responsePolicy) |
||||
} |
||||
case mstorage.BucketNameInvalid: |
||||
{ |
||||
error := errorCodeError(InvalidBucketName) |
||||
errorResponse := getErrorResponse(error, bucket) |
||||
w.WriteHeader(error.HttpStatusCode) |
||||
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) |
||||
} |
||||
case mstorage.BucketNotFound: |
||||
{ |
||||
error := errorCodeError(NoSuchBucket) |
||||
errorResponse := getErrorResponse(error, bucket) |
||||
w.WriteHeader(error.HttpStatusCode) |
||||
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) |
||||
} |
||||
case mstorage.BucketPolicyNotFound: |
||||
{ |
||||
error := errorCodeError(NoSuchBucketPolicy) |
||||
errorResponse := getErrorResponse(error, bucket) |
||||
w.WriteHeader(error.HttpStatusCode) |
||||
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) |
||||
} |
||||
case mstorage.BackendCorrupted: |
||||
case mstorage.ImplementationError: |
||||
{ |
||||
log.Println(err) |
||||
error := errorCodeError(InternalError) |
||||
errorResponse := getErrorResponse(error, bucket) |
||||
w.WriteHeader(error.HttpStatusCode) |
||||
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) |
||||
} |
||||
} |
||||
} |
||||
|
||||
func (server *minioApi) listObjectsHandler(w http.ResponseWriter, req *http.Request) { |
||||
vars := mux.Vars(req) |
||||
bucket := vars["bucket"] |
||||
|
||||
resources := getBucketResources(req.URL.Query()) |
||||
if resources.policy == true { |
||||
server.getBucketPolicyHandler(w, req) |
||||
return |
||||
} |
||||
|
||||
acceptsContentType := getContentType(req) |
||||
objects, isTruncated, err := server.storage.ListObjects(bucket, resources.prefix, 1000) |
||||
switch err := err.(type) { |
||||
case nil: // success
|
||||
{ |
||||
response := generateObjectsListResult(bucket, objects, isTruncated) |
||||
w.Write(writeObjectHeadersAndResponse(w, response, acceptsContentType)) |
||||
} |
||||
case mstorage.BucketNotFound: |
||||
{ |
||||
error := errorCodeError(NoSuchBucket) |
||||
errorResponse := getErrorResponse(error, bucket) |
||||
w.WriteHeader(error.HttpStatusCode) |
||||
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) |
||||
} |
||||
case mstorage.ImplementationError: |
||||
{ |
||||
// Embed error log on server side
|
||||
log.Println(err) |
||||
error := errorCodeError(InternalError) |
||||
errorResponse := getErrorResponse(error, bucket) |
||||
w.WriteHeader(error.HttpStatusCode) |
||||
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) |
||||
} |
||||
case mstorage.BucketNameInvalid: |
||||
{ |
||||
error := errorCodeError(InvalidBucketName) |
||||
errorResponse := getErrorResponse(error, bucket) |
||||
w.WriteHeader(error.HttpStatusCode) |
||||
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) |
||||
} |
||||
case mstorage.ObjectNameInvalid: |
||||
{ |
||||
error := errorCodeError(NoSuchKey) |
||||
errorResponse := getErrorResponse(error, resources.prefix) |
||||
w.WriteHeader(error.HttpStatusCode) |
||||
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) |
||||
} |
||||
} |
||||
} |
||||
|
||||
func (server *minioApi) listBucketsHandler(w http.ResponseWriter, req *http.Request) { |
||||
acceptsContentType := getContentType(req) |
||||
buckets, err := server.storage.ListBuckets() |
||||
switch err := err.(type) { |
||||
case nil: |
||||
{ |
||||
response := generateBucketsListResult(buckets) |
||||
w.Write(writeObjectHeadersAndResponse(w, response, acceptsContentType)) |
||||
} |
||||
case mstorage.ImplementationError: |
||||
{ |
||||
log.Println(err) |
||||
error := errorCodeError(InternalError) |
||||
errorResponse := getErrorResponse(error, "") |
||||
w.WriteHeader(error.HttpStatusCode) |
||||
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) |
||||
} |
||||
case mstorage.BackendCorrupted: |
||||
{ |
||||
log.Println(err) |
||||
error := errorCodeError(InternalError) |
||||
errorResponse := getErrorResponse(error, "") |
||||
w.WriteHeader(error.HttpStatusCode) |
||||
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) |
||||
} |
||||
} |
||||
} |
||||
|
||||
func (server *minioApi) putBucketHandler(w http.ResponseWriter, req *http.Request) { |
||||
vars := mux.Vars(req) |
||||
bucket := vars["bucket"] |
||||
err := server.storage.StoreBucket(bucket) |
||||
|
||||
resources := getBucketResources(req.URL.Query()) |
||||
if resources.policy == true { |
||||
server.putBucketPolicyHandler(w, req) |
||||
return |
||||
} |
||||
|
||||
acceptsContentType := getContentType(req) |
||||
switch err := err.(type) { |
||||
case nil: |
||||
{ |
||||
w.Header().Set("Server", "Minio") |
||||
w.Header().Set("Connection", "close") |
||||
} |
||||
case mstorage.BucketNameInvalid: |
||||
{ |
||||
error := errorCodeError(InvalidBucketName) |
||||
errorResponse := getErrorResponse(error, bucket) |
||||
w.WriteHeader(error.HttpStatusCode) |
||||
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) |
||||
} |
||||
case mstorage.BucketExists: |
||||
{ |
||||
error := errorCodeError(BucketAlreadyExists) |
||||
errorResponse := getErrorResponse(error, bucket) |
||||
w.WriteHeader(error.HttpStatusCode) |
||||
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) |
||||
} |
||||
case mstorage.ImplementationError: |
||||
{ |
||||
// Embed errors log on serve side
|
||||
log.Println(err) |
||||
error := errorCodeError(InternalError) |
||||
errorResponse := getErrorResponse(error, bucket) |
||||
w.WriteHeader(error.HttpStatusCode) |
||||
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) |
||||
} |
||||
} |
||||
} |
@ -1,376 +0,0 @@ |
||||
/* |
||||
* Mini Object Storage, (C) 2014 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 minioapi |
||||
|
||||
import ( |
||||
"log" |
||||
"net/http" |
||||
|
||||
"github.com/gorilla/mux" |
||||
mstorage "github.com/minio-io/minio/pkg/storage" |
||||
"github.com/minio-io/minio/pkg/utils/config" |
||||
) |
||||
|
||||
const ( |
||||
dateFormat = "2006-01-02T15:04:05.000Z" |
||||
) |
||||
|
||||
type minioApi struct { |
||||
storage mstorage.Storage |
||||
} |
||||
|
||||
// No encoder interface exists, so we create one.
|
||||
type encoder interface { |
||||
Encode(v interface{}) error |
||||
} |
||||
|
||||
func HttpHandler(storage mstorage.Storage) http.Handler { |
||||
mux := mux.NewRouter() |
||||
var api = minioApi{} |
||||
api.storage = storage |
||||
|
||||
var conf = config.Config{} |
||||
if err := conf.SetupConfig(); err != nil { |
||||
log.Fatal(err) |
||||
} |
||||
|
||||
mux.HandleFunc("/", api.listBucketsHandler).Methods("GET") |
||||
mux.HandleFunc("/{bucket}", api.listObjectsHandler).Methods("GET") |
||||
mux.HandleFunc("/{bucket}", api.putBucketHandler).Methods("PUT") |
||||
mux.HandleFunc("/{bucket}/{object:.*}", api.getObjectHandler).Methods("GET") |
||||
mux.HandleFunc("/{bucket}/{object:.*}", api.headObjectHandler).Methods("HEAD") |
||||
mux.HandleFunc("/{bucket}/{object:.*}", api.putObjectHandler).Methods("PUT") |
||||
|
||||
return validateHandler(conf, ignoreUnimplementedResources(mux)) |
||||
} |
||||
|
||||
func (server *minioApi) listBucketsHandler(w http.ResponseWriter, req *http.Request) { |
||||
vars := mux.Vars(req) |
||||
prefix, ok := vars["prefix"] |
||||
if !ok { |
||||
prefix = "" |
||||
} |
||||
|
||||
acceptsContentType := getContentType(req) |
||||
buckets, err := server.storage.ListBuckets(prefix) |
||||
switch err := err.(type) { |
||||
case nil: |
||||
{ |
||||
response := generateBucketsListResult(buckets) |
||||
w.Write(writeObjectHeadersAndResponse(w, response, acceptsContentType)) |
||||
} |
||||
case mstorage.BucketNameInvalid: |
||||
{ |
||||
error := errorCodeError(InvalidBucketName) |
||||
errorResponse := getErrorResponse(error, prefix) |
||||
w.WriteHeader(error.HttpStatusCode) |
||||
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) |
||||
} |
||||
case mstorage.ImplementationError: |
||||
{ |
||||
log.Println(err) |
||||
error := errorCodeError(InternalError) |
||||
errorResponse := getErrorResponse(error, prefix) |
||||
w.WriteHeader(error.HttpStatusCode) |
||||
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) |
||||
} |
||||
case mstorage.BackendCorrupted: |
||||
{ |
||||
log.Println(err) |
||||
error := errorCodeError(InternalError) |
||||
errorResponse := getErrorResponse(error, prefix) |
||||
w.WriteHeader(error.HttpStatusCode) |
||||
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) |
||||
} |
||||
} |
||||
} |
||||
|
||||
func (server *minioApi) listObjectsHandler(w http.ResponseWriter, req *http.Request) { |
||||
vars := mux.Vars(req) |
||||
bucket := vars["bucket"] |
||||
prefix, ok := vars["prefix"] |
||||
if !ok { |
||||
prefix = "" |
||||
} |
||||
|
||||
acceptsContentType := getContentType(req) |
||||
|
||||
objects, isTruncated, err := server.storage.ListObjects(bucket, prefix, 1000) |
||||
switch err := err.(type) { |
||||
case nil: // success
|
||||
{ |
||||
response := generateObjectsListResult(bucket, objects, isTruncated) |
||||
w.Write(writeObjectHeadersAndResponse(w, response, acceptsContentType)) |
||||
} |
||||
case mstorage.BucketNotFound: |
||||
{ |
||||
error := errorCodeError(NoSuchBucket) |
||||
errorResponse := getErrorResponse(error, bucket) |
||||
w.WriteHeader(error.HttpStatusCode) |
||||
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) |
||||
} |
||||
case mstorage.ImplementationError: |
||||
{ |
||||
// Embed error log on server side
|
||||
log.Println(err) |
||||
error := errorCodeError(InternalError) |
||||
errorResponse := getErrorResponse(error, bucket) |
||||
w.WriteHeader(error.HttpStatusCode) |
||||
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) |
||||
} |
||||
case mstorage.BucketNameInvalid: |
||||
{ |
||||
error := errorCodeError(InvalidBucketName) |
||||
errorResponse := getErrorResponse(error, bucket) |
||||
w.WriteHeader(error.HttpStatusCode) |
||||
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) |
||||
} |
||||
case mstorage.ObjectNameInvalid: |
||||
{ |
||||
error := errorCodeError(NoSuchKey) |
||||
errorResponse := getErrorResponse(error, prefix) |
||||
w.WriteHeader(error.HttpStatusCode) |
||||
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) |
||||
} |
||||
} |
||||
} |
||||
|
||||
func (server *minioApi) putBucketHandler(w http.ResponseWriter, req *http.Request) { |
||||
vars := mux.Vars(req) |
||||
bucket := vars["bucket"] |
||||
err := server.storage.StoreBucket(bucket) |
||||
|
||||
acceptsContentType := getContentType(req) |
||||
|
||||
switch err := err.(type) { |
||||
case nil: |
||||
{ |
||||
w.Header().Set("Server", "Minio") |
||||
w.Header().Set("Connection", "close") |
||||
} |
||||
case mstorage.BucketNameInvalid: |
||||
{ |
||||
error := errorCodeError(InvalidBucketName) |
||||
errorResponse := getErrorResponse(error, bucket) |
||||
w.WriteHeader(error.HttpStatusCode) |
||||
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) |
||||
} |
||||
case mstorage.BucketExists: |
||||
{ |
||||
error := errorCodeError(BucketAlreadyExists) |
||||
errorResponse := getErrorResponse(error, bucket) |
||||
w.WriteHeader(error.HttpStatusCode) |
||||
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) |
||||
} |
||||
case mstorage.ImplementationError: |
||||
{ |
||||
// Embed errors log on serve side
|
||||
log.Println(err) |
||||
error := errorCodeError(InternalError) |
||||
errorResponse := getErrorResponse(error, bucket) |
||||
w.WriteHeader(error.HttpStatusCode) |
||||
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) |
||||
} |
||||
} |
||||
} |
||||
|
||||
func (server *minioApi) getObjectHandler(w http.ResponseWriter, req *http.Request) { |
||||
vars := mux.Vars(req) |
||||
bucket := vars["bucket"] |
||||
object := vars["object"] |
||||
|
||||
acceptsContentType := getContentType(req) |
||||
|
||||
metadata, err := server.storage.GetObjectMetadata(bucket, object) |
||||
switch err := err.(type) { |
||||
case nil: // success
|
||||
{ |
||||
log.Println("Found: " + bucket + "#" + object) |
||||
writeObjectHeaders(w, metadata) |
||||
if _, err := server.storage.CopyObjectToWriter(w, bucket, object); err != nil { |
||||
log.Println(err) |
||||
} |
||||
} |
||||
case mstorage.ObjectNotFound: |
||||
{ |
||||
error := errorCodeError(NoSuchKey) |
||||
errorResponse := getErrorResponse(error, "/"+bucket+"/"+object) |
||||
w.WriteHeader(error.HttpStatusCode) |
||||
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) |
||||
} |
||||
case mstorage.ObjectNameInvalid: |
||||
{ |
||||
error := errorCodeError(NoSuchKey) |
||||
errorResponse := getErrorResponse(error, "/"+bucket+"/"+object) |
||||
w.WriteHeader(error.HttpStatusCode) |
||||
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) |
||||
} |
||||
case mstorage.BucketNameInvalid: |
||||
{ |
||||
error := errorCodeError(InvalidBucketName) |
||||
errorResponse := getErrorResponse(error, "/"+bucket+"/"+object) |
||||
w.WriteHeader(error.HttpStatusCode) |
||||
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) |
||||
} |
||||
case mstorage.ImplementationError: |
||||
{ |
||||
// Embed errors log on serve side
|
||||
log.Println(err) |
||||
error := errorCodeError(InternalError) |
||||
errorResponse := getErrorResponse(error, "/"+bucket+"/"+object) |
||||
w.WriteHeader(error.HttpStatusCode) |
||||
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) |
||||
} |
||||
} |
||||
} |
||||
|
||||
func (server *minioApi) headObjectHandler(w http.ResponseWriter, req *http.Request) { |
||||
vars := mux.Vars(req) |
||||
bucket := vars["bucket"] |
||||
object := vars["object"] |
||||
|
||||
acceptsContentType := getContentType(req) |
||||
|
||||
metadata, err := server.storage.GetObjectMetadata(bucket, object) |
||||
switch err := err.(type) { |
||||
case nil: |
||||
writeObjectHeaders(w, metadata) |
||||
case mstorage.ObjectNotFound: |
||||
{ |
||||
error := errorCodeError(NoSuchKey) |
||||
errorResponse := getErrorResponse(error, "/"+bucket+"/"+object) |
||||
w.WriteHeader(error.HttpStatusCode) |
||||
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) |
||||
} |
||||
case mstorage.ObjectNameInvalid: |
||||
{ |
||||
error := errorCodeError(NoSuchKey) |
||||
errorResponse := getErrorResponse(error, "/"+bucket+"/"+object) |
||||
w.WriteHeader(error.HttpStatusCode) |
||||
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) |
||||
} |
||||
case mstorage.ImplementationError: |
||||
{ |
||||
// Embed error log on server side
|
||||
log.Println(err) |
||||
error := errorCodeError(InternalError) |
||||
errorResponse := getErrorResponse(error, "/"+bucket+"/"+object) |
||||
w.WriteHeader(error.HttpStatusCode) |
||||
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) |
||||
} |
||||
} |
||||
} |
||||
|
||||
func (server *minioApi) putObjectHandler(w http.ResponseWriter, req *http.Request) { |
||||
vars := mux.Vars(req) |
||||
bucket := vars["bucket"] |
||||
object := vars["object"] |
||||
|
||||
acceptsContentType := getContentType(req) |
||||
|
||||
err := server.storage.StoreObject(bucket, object, "", req.Body) |
||||
switch err := err.(type) { |
||||
case nil: |
||||
w.Header().Set("Server", "Minio") |
||||
w.Header().Set("Connection", "close") |
||||
case mstorage.ImplementationError: |
||||
{ |
||||
// Embed error log on server side
|
||||
log.Println(err) |
||||
error := errorCodeError(InternalError) |
||||
errorResponse := getErrorResponse(error, "/"+bucket+"/"+object) |
||||
w.WriteHeader(error.HttpStatusCode) |
||||
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) |
||||
} |
||||
case mstorage.BucketNotFound: |
||||
{ |
||||
error := errorCodeError(NoSuchBucket) |
||||
errorResponse := getErrorResponse(error, "/"+bucket+"/"+object) |
||||
w.WriteHeader(error.HttpStatusCode) |
||||
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) |
||||
} |
||||
case mstorage.BucketNameInvalid: |
||||
{ |
||||
error := errorCodeError(InvalidBucketName) |
||||
errorResponse := getErrorResponse(error, "/"+bucket+"/"+object) |
||||
w.WriteHeader(error.HttpStatusCode) |
||||
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) |
||||
} |
||||
case mstorage.ObjectExists: |
||||
{ |
||||
error := errorCodeError(NotImplemented) |
||||
errorResponse := getErrorResponse(error, "/"+bucket+"/"+object) |
||||
w.WriteHeader(error.HttpStatusCode) |
||||
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) |
||||
} |
||||
} |
||||
|
||||
} |
||||
|
||||
func generateBucketsListResult(buckets []mstorage.BucketMetadata) BucketListResponse { |
||||
var listbuckets []*Bucket |
||||
var data = BucketListResponse{} |
||||
var owner = Owner{} |
||||
|
||||
owner.ID = "minio" |
||||
owner.DisplayName = "minio" |
||||
|
||||
for _, bucket := range buckets { |
||||
var listbucket = &Bucket{} |
||||
listbucket.Name = bucket.Name |
||||
listbucket.CreationDate = bucket.Created.Format(dateFormat) |
||||
listbuckets = append(listbuckets, listbucket) |
||||
} |
||||
|
||||
data.Owner = owner |
||||
data.Buckets.Bucket = listbuckets |
||||
|
||||
return data |
||||
} |
||||
|
||||
// takes a set of objects and prepares the objects for serialization
|
||||
// input:
|
||||
// bucket name
|
||||
// array of object metadata
|
||||
// results truncated flag
|
||||
//
|
||||
// output:
|
||||
// populated struct that can be serialized to match xml and json api spec output
|
||||
func generateObjectsListResult(bucket string, objects []mstorage.ObjectMetadata, isTruncated bool) ObjectListResponse { |
||||
var contents []*Item |
||||
var owner = Owner{} |
||||
var data = ObjectListResponse{} |
||||
|
||||
owner.ID = "minio" |
||||
owner.DisplayName = "minio" |
||||
|
||||
for _, object := range objects { |
||||
var content = &Item{} |
||||
content.Key = object.Key |
||||
content.LastModified = object.Created.Format(dateFormat) |
||||
content.ETag = object.ETag |
||||
content.Size = object.Size |
||||
content.StorageClass = "STANDARD" |
||||
content.Owner = owner |
||||
contents = append(contents, content) |
||||
} |
||||
data.Name = bucket |
||||
data.Contents = contents |
||||
data.MaxKeys = MAX_OBJECT_LIST |
||||
data.IsTruncated = isTruncated |
||||
return data |
||||
} |
@ -0,0 +1,143 @@ |
||||
package minioapi |
||||
|
||||
import ( |
||||
"log" |
||||
"net/http" |
||||
|
||||
"github.com/gorilla/mux" |
||||
mstorage "github.com/minio-io/minio/pkg/storage" |
||||
) |
||||
|
||||
func (server *minioApi) getObjectHandler(w http.ResponseWriter, req *http.Request) { |
||||
var object, bucket string |
||||
|
||||
acceptsContentType := getContentType(req) |
||||
vars := mux.Vars(req) |
||||
bucket = vars["bucket"] |
||||
object = vars["object"] |
||||
|
||||
metadata, err := server.storage.GetObjectMetadata(bucket, object) |
||||
switch err := err.(type) { |
||||
case nil: // success
|
||||
{ |
||||
log.Println("Found: " + bucket + "#" + object) |
||||
writeObjectHeaders(w, metadata) |
||||
if _, err := server.storage.CopyObjectToWriter(w, bucket, object); err != nil { |
||||
log.Println(err) |
||||
} |
||||
} |
||||
case mstorage.ObjectNotFound: |
||||
{ |
||||
error := errorCodeError(NoSuchKey) |
||||
errorResponse := getErrorResponse(error, "/"+bucket+"/"+object) |
||||
w.WriteHeader(error.HttpStatusCode) |
||||
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) |
||||
} |
||||
case mstorage.ObjectNameInvalid: |
||||
{ |
||||
error := errorCodeError(NoSuchKey) |
||||
errorResponse := getErrorResponse(error, "/"+bucket+"/"+object) |
||||
w.WriteHeader(error.HttpStatusCode) |
||||
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) |
||||
} |
||||
case mstorage.BucketNameInvalid: |
||||
{ |
||||
error := errorCodeError(InvalidBucketName) |
||||
errorResponse := getErrorResponse(error, "/"+bucket+"/"+object) |
||||
w.WriteHeader(error.HttpStatusCode) |
||||
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) |
||||
} |
||||
case mstorage.ImplementationError: |
||||
{ |
||||
// Embed errors log on serve side
|
||||
log.Println(err) |
||||
error := errorCodeError(InternalError) |
||||
errorResponse := getErrorResponse(error, "/"+bucket+"/"+object) |
||||
w.WriteHeader(error.HttpStatusCode) |
||||
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) |
||||
} |
||||
} |
||||
} |
||||
|
||||
func (server *minioApi) headObjectHandler(w http.ResponseWriter, req *http.Request) { |
||||
var object, bucket string |
||||
acceptsContentType := getContentType(req) |
||||
vars := mux.Vars(req) |
||||
bucket = vars["bucket"] |
||||
object = vars["object"] |
||||
|
||||
metadata, err := server.storage.GetObjectMetadata(bucket, object) |
||||
switch err := err.(type) { |
||||
case nil: |
||||
writeObjectHeaders(w, metadata) |
||||
case mstorage.ObjectNotFound: |
||||
{ |
||||
error := errorCodeError(NoSuchKey) |
||||
errorResponse := getErrorResponse(error, "/"+bucket+"/"+object) |
||||
w.WriteHeader(error.HttpStatusCode) |
||||
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) |
||||
} |
||||
case mstorage.ObjectNameInvalid: |
||||
{ |
||||
error := errorCodeError(NoSuchKey) |
||||
errorResponse := getErrorResponse(error, "/"+bucket+"/"+object) |
||||
w.WriteHeader(error.HttpStatusCode) |
||||
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) |
||||
} |
||||
case mstorage.ImplementationError: |
||||
{ |
||||
// Embed error log on server side
|
||||
log.Println(err) |
||||
error := errorCodeError(InternalError) |
||||
errorResponse := getErrorResponse(error, "/"+bucket+"/"+object) |
||||
w.WriteHeader(error.HttpStatusCode) |
||||
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) |
||||
} |
||||
} |
||||
} |
||||
|
||||
func (server *minioApi) putObjectHandler(w http.ResponseWriter, req *http.Request) { |
||||
var object, bucket string |
||||
vars := mux.Vars(req) |
||||
acceptsContentType := getContentType(req) |
||||
bucket = vars["bucket"] |
||||
object = vars["object"] |
||||
|
||||
err := server.storage.StoreObject(bucket, object, "", req.Body) |
||||
switch err := err.(type) { |
||||
case nil: |
||||
w.Header().Set("Server", "Minio") |
||||
w.Header().Set("Connection", "close") |
||||
case mstorage.ImplementationError: |
||||
{ |
||||
// Embed error log on server side
|
||||
log.Println(err) |
||||
error := errorCodeError(InternalError) |
||||
errorResponse := getErrorResponse(error, "/"+bucket+"/"+object) |
||||
w.WriteHeader(error.HttpStatusCode) |
||||
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) |
||||
} |
||||
case mstorage.BucketNotFound: |
||||
{ |
||||
error := errorCodeError(NoSuchBucket) |
||||
errorResponse := getErrorResponse(error, "/"+bucket+"/"+object) |
||||
w.WriteHeader(error.HttpStatusCode) |
||||
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) |
||||
} |
||||
case mstorage.BucketNameInvalid: |
||||
{ |
||||
error := errorCodeError(InvalidBucketName) |
||||
errorResponse := getErrorResponse(error, "/"+bucket+"/"+object) |
||||
w.WriteHeader(error.HttpStatusCode) |
||||
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) |
||||
} |
||||
case mstorage.ObjectExists: |
||||
{ |
||||
error := errorCodeError(NotImplemented) |
||||
errorResponse := getErrorResponse(error, "/"+bucket+"/"+object) |
||||
w.WriteHeader(error.HttpStatusCode) |
||||
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) |
||||
} |
||||
} |
||||
|
||||
} |
@ -0,0 +1,32 @@ |
||||
/* |
||||
* Mini 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 minioapi |
||||
|
||||
import ( |
||||
"net/http" |
||||
) |
||||
|
||||
type pHandler struct { |
||||
handler http.Handler |
||||
} |
||||
|
||||
func policyHandler(h http.Handler) http.Handler { |
||||
return pHandler{h} |
||||
} |
||||
|
||||
func (p pHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { |
||||
} |
@ -0,0 +1,33 @@ |
||||
package minioapi |
||||
|
||||
import ( |
||||
"net/url" |
||||
"strconv" |
||||
) |
||||
|
||||
type bucketResources struct { |
||||
prefix string |
||||
marker string |
||||
maxkeys int |
||||
policy bool |
||||
delimiter string |
||||
// uploads bool - TODO implemented with multipart support
|
||||
} |
||||
|
||||
func getBucketResources(values url.Values) (v bucketResources) { |
||||
for key, value := range values { |
||||
switch true { |
||||
case key == "prefix": |
||||
v.prefix = value[0] |
||||
case key == "marker": |
||||
v.marker = value[0] |
||||
case key == "maxkeys": |
||||
v.maxkeys, _ = strconv.Atoi(value[0]) |
||||
case key == "policy": |
||||
v.policy = true |
||||
case key == "delimiter": |
||||
v.delimiter = value[0] |
||||
} |
||||
} |
||||
return |
||||
} |
@ -0,0 +1,59 @@ |
||||
package minioapi |
||||
|
||||
import ( |
||||
mstorage "github.com/minio-io/minio/pkg/storage" |
||||
) |
||||
|
||||
func generateBucketsListResult(buckets []mstorage.BucketMetadata) BucketListResponse { |
||||
var listbuckets []*Bucket |
||||
var data = BucketListResponse{} |
||||
var owner = Owner{} |
||||
|
||||
owner.ID = "minio" |
||||
owner.DisplayName = "minio" |
||||
|
||||
for _, bucket := range buckets { |
||||
var listbucket = &Bucket{} |
||||
listbucket.Name = bucket.Name |
||||
listbucket.CreationDate = bucket.Created.Format(dateFormat) |
||||
listbuckets = append(listbuckets, listbucket) |
||||
} |
||||
|
||||
data.Owner = owner |
||||
data.Buckets.Bucket = listbuckets |
||||
|
||||
return data |
||||
} |
||||
|
||||
// takes a set of objects and prepares the objects for serialization
|
||||
// input:
|
||||
// bucket name
|
||||
// array of object metadata
|
||||
// results truncated flag
|
||||
//
|
||||
// output:
|
||||
// populated struct that can be serialized to match xml and json api spec output
|
||||
func generateObjectsListResult(bucket string, objects []mstorage.ObjectMetadata, isTruncated bool) ObjectListResponse { |
||||
var contents []*Item |
||||
var owner = Owner{} |
||||
var data = ObjectListResponse{} |
||||
|
||||
owner.ID = "minio" |
||||
owner.DisplayName = "minio" |
||||
|
||||
for _, object := range objects { |
||||
var content = &Item{} |
||||
content.Key = object.Key |
||||
content.LastModified = object.Created.Format(dateFormat) |
||||
content.ETag = object.ETag |
||||
content.Size = object.Size |
||||
content.StorageClass = "STANDARD" |
||||
content.Owner = owner |
||||
contents = append(contents, content) |
||||
} |
||||
data.Name = bucket |
||||
data.Contents = contents |
||||
data.MaxKeys = MAX_OBJECT_LIST |
||||
data.IsTruncated = isTruncated |
||||
return data |
||||
} |
@ -0,0 +1,59 @@ |
||||
/* |
||||
* Mini Object Storage, (C) 2014 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 minioapi |
||||
|
||||
import ( |
||||
"log" |
||||
"net/http" |
||||
|
||||
"github.com/gorilla/mux" |
||||
mstorage "github.com/minio-io/minio/pkg/storage" |
||||
"github.com/minio-io/minio/pkg/utils/config" |
||||
) |
||||
|
||||
const ( |
||||
dateFormat = "2006-01-02T15:04:05.000Z" |
||||
) |
||||
|
||||
type minioApi struct { |
||||
storage mstorage.Storage |
||||
} |
||||
|
||||
// No encoder interface exists, so we create one.
|
||||
type encoder interface { |
||||
Encode(v interface{}) error |
||||
} |
||||
|
||||
func HttpHandler(storage mstorage.Storage) http.Handler { |
||||
mux := mux.NewRouter() |
||||
var api = minioApi{} |
||||
api.storage = storage |
||||
|
||||
var conf = config.Config{} |
||||
if err := conf.SetupConfig(); err != nil { |
||||
log.Fatal(err) |
||||
} |
||||
|
||||
mux.HandleFunc("/", api.listBucketsHandler).Methods("GET") |
||||
mux.HandleFunc("/{bucket}", api.listObjectsHandler).Methods("GET") |
||||
mux.HandleFunc("/{bucket}", api.putBucketHandler).Methods("PUT") |
||||
mux.HandleFunc("/{bucket}/{object:.*}", api.getObjectHandler).Methods("GET") |
||||
mux.HandleFunc("/{bucket}/{object:.*}", api.headObjectHandler).Methods("HEAD") |
||||
mux.HandleFunc("/{bucket}/{object:.*}", api.putObjectHandler).Methods("PUT") |
||||
|
||||
return validateHandler(conf, ignoreUnimplementedResources(mux)) |
||||
} |
@ -0,0 +1,60 @@ |
||||
package policy |
||||
|
||||
import ( |
||||
"fmt" |
||||
"strconv" |
||||
"strings" |
||||
) |
||||
|
||||
// For 0000-00-00 Date type
|
||||
type Date struct { |
||||
Year int16 |
||||
Month byte |
||||
Day byte |
||||
} |
||||
|
||||
func (d Date) String() string { |
||||
return fmt.Sprintf("%04d-%02d-%02d", d.Year, d.Month, d.Day) |
||||
} |
||||
|
||||
// True if date is 0000-00-00
|
||||
func (d Date) IsZero() bool { |
||||
return d.Day == 0 && d.Month == 0 && d.Year == 0 |
||||
} |
||||
|
||||
// Convert string date in format YYYY-MM-DD to Date.
|
||||
// Leading and trailing spaces are ignored. If format is invalid returns zero.
|
||||
func ParseDate(str string) (d Date, err error) { |
||||
str = strings.TrimSpace(str) |
||||
if str == "0000-00-00" { |
||||
return |
||||
} |
||||
var ( |
||||
y, m, n int |
||||
) |
||||
if len(str) != 10 || str[4] != '-' || str[7] != '-' { |
||||
err = fmt.Errorf("Invalid 0000-00-000 style DATE string: " + str) |
||||
return |
||||
} |
||||
if y, err = strconv.Atoi(str[0:4]); err != nil { |
||||
return |
||||
} |
||||
if m, err = strconv.Atoi(str[5:7]); err != nil { |
||||
return |
||||
} |
||||
if m < 1 || m > 12 { |
||||
err = fmt.Errorf("Invalid 0000-00-000 style DATE string: " + str) |
||||
return |
||||
} |
||||
if n, err = strconv.Atoi(str[8:10]); err != nil { |
||||
return |
||||
} |
||||
if n < 1 || n > 31 { |
||||
err = fmt.Errorf("Invalid 0000-00-000 style DATE string: " + str) |
||||
return |
||||
} |
||||
d.Year = int16(y) |
||||
d.Month = byte(m) |
||||
d.Day = byte(n) |
||||
return |
||||
} |
@ -0,0 +1,67 @@ |
||||
package policy |
||||
|
||||
import ( |
||||
"encoding/json" |
||||
"io" |
||||
) |
||||
|
||||
type UserCred struct { |
||||
AWS string |
||||
} |
||||
|
||||
type Stmt struct { |
||||
Sid string |
||||
Effect string |
||||
Principal UserCred |
||||
Action []string |
||||
Resource []string |
||||
} |
||||
|
||||
type BucketPolicy struct { |
||||
Version string // date in 0000-00-00 format
|
||||
Statement []Stmt |
||||
} |
||||
|
||||
// TODO: Add more checks
|
||||
|
||||
// validate request body is proper JSON
|
||||
func Parsepolicy(data io.Reader) (BucketPolicy, bool) { |
||||
var policy BucketPolicy |
||||
decoder := json.NewDecoder(data) |
||||
err := decoder.Decode(&policy) |
||||
if err != nil { |
||||
goto error |
||||
} |
||||
if len(policy.Version) == 0 { |
||||
goto error |
||||
} |
||||
_, err = ParseDate(policy.Version) |
||||
if err != nil { |
||||
goto error |
||||
} |
||||
if len(policy.Statement) == 0 { |
||||
goto error |
||||
} |
||||
|
||||
for _, statement := range policy.Statement { |
||||
if len(statement.Sid) == 0 { |
||||
goto error |
||||
} |
||||
if len(statement.Effect) == 0 { |
||||
goto error |
||||
} |
||||
if len(statement.Principal.AWS) == 0 { |
||||
goto error |
||||
} |
||||
if len(statement.Action) == 0 { |
||||
goto error |
||||
} |
||||
if len(statement.Resource) == 0 { |
||||
goto error |
||||
} |
||||
} |
||||
return policy, true |
||||
|
||||
error: |
||||
return BucketPolicy{}, false |
||||
} |
Loading…
Reference in new issue