Merge pull request #257 from harshavardhana/pr_out_update_contributing_guide

This commit is contained in:
Harshavardhana 2015-03-05 23:39:25 -08:00
commit 02ccf123c9
41 changed files with 381 additions and 370 deletions

View File

@ -54,7 +54,8 @@ Building Libraries
- Run `make save` from top-level directory (or `godep restore && godep save ./...`). - Run `make save` from top-level directory (or `godep restore && godep save ./...`).
* When you're ready to create a pull request, be sure to: * When you're ready to create a pull request, be sure to:
- Have test cases for the new code. If you have questions about how to do it, please ask in your pull request. - Have test cases for the new code. If you have questions about how to do it, please ask in your pull request.
- Run `go fmt` - Run `go fmt
- Run `golint` (`go get github.com/golang/lint/golint`)
- Squash your commits into a single commit. `git rebase -i`. It's okay to force update your pull request. - Squash your commits into a single commit. `git rebase -i`. It's okay to force update your pull request.
- Make sure `go test -race ./...` and `go build` completes. - Make sure `go test -race ./...` and `go build` completes.
* Read [Effective Go](https://github.com/golang/go/wiki/CodeReviewComments) article from Golang project * Read [Effective Go](https://github.com/golang/go/wiki/CodeReviewComments) article from Golang project

20
main.go
View File

@ -27,14 +27,14 @@ import (
func getStorageType(input string) server.StorageType { func getStorageType(input string) server.StorageType {
switch { switch {
case input == "file": case input == "file":
return server.FileStorage return server.File
case input == "inmemory": case input == "inmemory":
return server.InMemoryStorage return server.InMemory
default: default:
{ {
log.Println("Unknown storage type:", input) log.Println("Unknown storage type:", input)
log.Println("Choosing default storage type as 'file'..") log.Println("Choosing default storage type as 'file'..")
return server.FileStorage return server.File
} }
} }
} }
@ -51,24 +51,24 @@ func runCmd(c *cli.Context) {
} }
tls := (certFile != "" && keyFile != "") tls := (certFile != "" && keyFile != "")
storageType := getStorageType(storageTypeStr) storageType := getStorageType(storageTypeStr)
var serverConfigs []server.ServerConfig var serverConfigs []server.Config
apiServerConfig := server.ServerConfig{ apiServerConfig := server.Config{
Domain: domain, Domain: domain,
Address: apiaddress, Address: apiaddress,
Tls: tls, TLS: tls,
CertFile: certFile, CertFile: certFile,
KeyFile: keyFile, KeyFile: keyFile,
ApiType: server.MinioApi{ APIType: server.MinioAPI{
StorageType: storageType, StorageType: storageType,
}, },
} }
webUIServerConfig := server.ServerConfig{ webUIServerConfig := server.Config{
Domain: domain, Domain: domain,
Address: webaddress, Address: webaddress,
Tls: false, TLS: false,
CertFile: "", CertFile: "",
KeyFile: "", KeyFile: "",
ApiType: server.WebUIApi{ APIType: server.WebAPI{
Websocket: false, Websocket: false,
}, },
} }

View File

@ -41,7 +41,7 @@ var _ = Suite(&MySuite{})
func (s *MySuite) TestNonExistantObject(c *C) { func (s *MySuite) TestNonExistantObject(c *C) {
_, _, storage := inmemory.Start() _, _, storage := inmemory.Start()
httpHandler := HttpHandler("", storage) httpHandler := HTTPHandler("", storage)
testServer := httptest.NewServer(httpHandler) testServer := httptest.NewServer(httpHandler)
defer testServer.Close() defer testServer.Close()
@ -53,7 +53,7 @@ func (s *MySuite) TestNonExistantObject(c *C) {
func (s *MySuite) TestEmptyObject(c *C) { func (s *MySuite) TestEmptyObject(c *C) {
_, _, storage := inmemory.Start() _, _, storage := inmemory.Start()
httpHandler := HttpHandler("", storage) httpHandler := HTTPHandler("", storage)
testServer := httptest.NewServer(httpHandler) testServer := httptest.NewServer(httpHandler)
defer testServer.Close() defer testServer.Close()
@ -78,7 +78,7 @@ func (s *MySuite) TestEmptyObject(c *C) {
func (s *MySuite) TestObject(c *C) { func (s *MySuite) TestObject(c *C) {
_, _, storage := inmemory.Start() _, _, storage := inmemory.Start()
httpHandler := HttpHandler("", storage) httpHandler := HTTPHandler("", storage)
testServer := httptest.NewServer(httpHandler) testServer := httptest.NewServer(httpHandler)
defer testServer.Close() defer testServer.Close()
@ -101,7 +101,7 @@ func (s *MySuite) TestObject(c *C) {
func (s *MySuite) TestMultipleObjects(c *C) { func (s *MySuite) TestMultipleObjects(c *C) {
_, _, storage := inmemory.Start() _, _, storage := inmemory.Start()
httpHandler := HttpHandler("", storage) httpHandler := HTTPHandler("", storage)
testServer := httptest.NewServer(httpHandler) testServer := httptest.NewServer(httpHandler)
defer testServer.Close() defer testServer.Close()
@ -181,7 +181,7 @@ func (s *MySuite) TestMultipleObjects(c *C) {
func (s *MySuite) TestNotImplemented(c *C) { func (s *MySuite) TestNotImplemented(c *C) {
_, _, storage := inmemory.Start() _, _, storage := inmemory.Start()
httpHandler := HttpHandler("", storage) httpHandler := HTTPHandler("", storage)
testServer := httptest.NewServer(httpHandler) testServer := httptest.NewServer(httpHandler)
defer testServer.Close() defer testServer.Close()
@ -192,7 +192,7 @@ func (s *MySuite) TestNotImplemented(c *C) {
func (s *MySuite) TestHeader(c *C) { func (s *MySuite) TestHeader(c *C) {
_, _, storage := inmemory.Start() _, _, storage := inmemory.Start()
httpHandler := HttpHandler("", storage) httpHandler := HTTPHandler("", storage)
testServer := httptest.NewServer(httpHandler) testServer := httptest.NewServer(httpHandler)
defer testServer.Close() defer testServer.Close()
@ -215,7 +215,7 @@ func (s *MySuite) TestHeader(c *C) {
func (s *MySuite) TestPutBucket(c *C) { func (s *MySuite) TestPutBucket(c *C) {
_, _, storage := inmemory.Start() _, _, storage := inmemory.Start()
httpHandler := HttpHandler("", storage) httpHandler := HTTPHandler("", storage)
testServer := httptest.NewServer(httpHandler) testServer := httptest.NewServer(httpHandler)
defer testServer.Close() defer testServer.Close()
@ -240,7 +240,7 @@ func (s *MySuite) TestPutBucket(c *C) {
func (s *MySuite) TestPutObject(c *C) { func (s *MySuite) TestPutObject(c *C) {
_, _, storage := inmemory.Start() _, _, storage := inmemory.Start()
httpHandler := HttpHandler("", storage) httpHandler := HTTPHandler("", storage)
testServer := httptest.NewServer(httpHandler) testServer := httptest.NewServer(httpHandler)
defer testServer.Close() defer testServer.Close()
@ -297,7 +297,7 @@ func (s *MySuite) TestPutObject(c *C) {
func (s *MySuite) TestListBuckets(c *C) { func (s *MySuite) TestListBuckets(c *C) {
_, _, storage := inmemory.Start() _, _, storage := inmemory.Start()
httpHandler := HttpHandler("", storage) httpHandler := HTTPHandler("", storage)
testServer := httptest.NewServer(httpHandler) testServer := httptest.NewServer(httpHandler)
defer testServer.Close() defer testServer.Close()
@ -376,7 +376,7 @@ func verifyHeaders(c *C, header http.Header, date time.Time, size int, contentTy
func (s *MySuite) TestXMLNameNotInBucketListJson(c *C) { func (s *MySuite) TestXMLNameNotInBucketListJson(c *C) {
_, _, storage := inmemory.Start() _, _, storage := inmemory.Start()
httpHandler := HttpHandler("", storage) httpHandler := HTTPHandler("", storage)
testServer := httptest.NewServer(httpHandler) testServer := httptest.NewServer(httpHandler)
defer testServer.Close() defer testServer.Close()
@ -401,7 +401,7 @@ func (s *MySuite) TestXMLNameNotInBucketListJson(c *C) {
func (s *MySuite) TestXMLNameNotInObjectListJson(c *C) { func (s *MySuite) TestXMLNameNotInObjectListJson(c *C) {
_, _, storage := inmemory.Start() _, _, storage := inmemory.Start()
httpHandler := HttpHandler("", storage) httpHandler := HTTPHandler("", storage)
testServer := httptest.NewServer(httpHandler) testServer := httptest.NewServer(httpHandler)
defer testServer.Close() defer testServer.Close()
@ -426,7 +426,7 @@ func (s *MySuite) TestXMLNameNotInObjectListJson(c *C) {
func (s *MySuite) TestContentTypePersists(c *C) { func (s *MySuite) TestContentTypePersists(c *C) {
_, _, storage := inmemory.Start() _, _, storage := inmemory.Start()
httpHandler := HttpHandler("", storage) httpHandler := HTTPHandler("", storage)
testServer := httptest.NewServer(httpHandler) testServer := httptest.NewServer(httpHandler)
defer testServer.Close() defer testServer.Close()

View File

@ -30,7 +30,7 @@ import (
// of the objects in a bucket. You can use the request parameters as selection // of the objects in a bucket. You can use the request parameters as selection
// criteria to return a subset of the objects in a bucket. // criteria to return a subset of the objects in a bucket.
// //
func (server *minioApi) listObjectsHandler(w http.ResponseWriter, req *http.Request) { func (server *minioAPI) listObjectsHandler(w http.ResponseWriter, req *http.Request) {
vars := mux.Vars(req) vars := mux.Vars(req)
bucket := vars["bucket"] bucket := vars["bucket"]
@ -56,7 +56,7 @@ func (server *minioApi) listObjectsHandler(w http.ResponseWriter, req *http.Requ
{ {
error := errorCodeError(NoSuchBucket) error := errorCodeError(NoSuchBucket)
errorResponse := getErrorResponse(error, bucket) errorResponse := getErrorResponse(error, bucket)
w.WriteHeader(error.HttpStatusCode) w.WriteHeader(error.HTTPStatusCode)
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) w.Write(writeErrorResponse(w, errorResponse, acceptsContentType))
} }
case mstorage.ImplementationError: case mstorage.ImplementationError:
@ -65,21 +65,21 @@ func (server *minioApi) listObjectsHandler(w http.ResponseWriter, req *http.Requ
log.Println(err) log.Println(err)
error := errorCodeError(InternalError) error := errorCodeError(InternalError)
errorResponse := getErrorResponse(error, bucket) errorResponse := getErrorResponse(error, bucket)
w.WriteHeader(error.HttpStatusCode) w.WriteHeader(error.HTTPStatusCode)
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) w.Write(writeErrorResponse(w, errorResponse, acceptsContentType))
} }
case mstorage.BucketNameInvalid: case mstorage.BucketNameInvalid:
{ {
error := errorCodeError(InvalidBucketName) error := errorCodeError(InvalidBucketName)
errorResponse := getErrorResponse(error, bucket) errorResponse := getErrorResponse(error, bucket)
w.WriteHeader(error.HttpStatusCode) w.WriteHeader(error.HTTPStatusCode)
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) w.Write(writeErrorResponse(w, errorResponse, acceptsContentType))
} }
case mstorage.ObjectNameInvalid: case mstorage.ObjectNameInvalid:
{ {
error := errorCodeError(NoSuchKey) error := errorCodeError(NoSuchKey)
errorResponse := getErrorResponse(error, resources.Prefix) errorResponse := getErrorResponse(error, resources.Prefix)
w.WriteHeader(error.HttpStatusCode) w.WriteHeader(error.HTTPStatusCode)
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) w.Write(writeErrorResponse(w, errorResponse, acceptsContentType))
} }
} }
@ -89,7 +89,7 @@ func (server *minioApi) listObjectsHandler(w http.ResponseWriter, req *http.Requ
// ----------- // -----------
// This implementation of the GET operation returns a list of all buckets // This implementation of the GET operation returns a list of all buckets
// owned by the authenticated sender of the request. // owned by the authenticated sender of the request.
func (server *minioApi) listBucketsHandler(w http.ResponseWriter, req *http.Request) { func (server *minioAPI) listBucketsHandler(w http.ResponseWriter, req *http.Request) {
acceptsContentType := getContentType(req) acceptsContentType := getContentType(req)
buckets, err := server.storage.ListBuckets() buckets, err := server.storage.ListBuckets()
switch err := err.(type) { switch err := err.(type) {
@ -103,7 +103,7 @@ func (server *minioApi) listBucketsHandler(w http.ResponseWriter, req *http.Requ
log.Println(err) log.Println(err)
error := errorCodeError(InternalError) error := errorCodeError(InternalError)
errorResponse := getErrorResponse(error, "") errorResponse := getErrorResponse(error, "")
w.WriteHeader(error.HttpStatusCode) w.WriteHeader(error.HTTPStatusCode)
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) w.Write(writeErrorResponse(w, errorResponse, acceptsContentType))
} }
case mstorage.BackendCorrupted: case mstorage.BackendCorrupted:
@ -111,7 +111,7 @@ func (server *minioApi) listBucketsHandler(w http.ResponseWriter, req *http.Requ
log.Println(err) log.Println(err)
error := errorCodeError(InternalError) error := errorCodeError(InternalError)
errorResponse := getErrorResponse(error, "") errorResponse := getErrorResponse(error, "")
w.WriteHeader(error.HttpStatusCode) w.WriteHeader(error.HTTPStatusCode)
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) w.Write(writeErrorResponse(w, errorResponse, acceptsContentType))
} }
} }
@ -120,7 +120,7 @@ func (server *minioApi) listBucketsHandler(w http.ResponseWriter, req *http.Requ
// PUT Bucket // PUT Bucket
// ---------- // ----------
// This implementation of the PUT operation creates a new bucket for authenticated request // This implementation of the PUT operation creates a new bucket for authenticated request
func (server *minioApi) putBucketHandler(w http.ResponseWriter, req *http.Request) { func (server *minioAPI) putBucketHandler(w http.ResponseWriter, req *http.Request) {
vars := mux.Vars(req) vars := mux.Vars(req)
bucket := vars["bucket"] bucket := vars["bucket"]
err := server.storage.StoreBucket(bucket) err := server.storage.StoreBucket(bucket)
@ -142,14 +142,14 @@ func (server *minioApi) putBucketHandler(w http.ResponseWriter, req *http.Reques
{ {
error := errorCodeError(InvalidBucketName) error := errorCodeError(InvalidBucketName)
errorResponse := getErrorResponse(error, bucket) errorResponse := getErrorResponse(error, bucket)
w.WriteHeader(error.HttpStatusCode) w.WriteHeader(error.HTTPStatusCode)
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) w.Write(writeErrorResponse(w, errorResponse, acceptsContentType))
} }
case mstorage.BucketExists: case mstorage.BucketExists:
{ {
error := errorCodeError(BucketAlreadyExists) error := errorCodeError(BucketAlreadyExists)
errorResponse := getErrorResponse(error, bucket) errorResponse := getErrorResponse(error, bucket)
w.WriteHeader(error.HttpStatusCode) w.WriteHeader(error.HTTPStatusCode)
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) w.Write(writeErrorResponse(w, errorResponse, acceptsContentType))
} }
case mstorage.ImplementationError: case mstorage.ImplementationError:
@ -158,7 +158,7 @@ func (server *minioApi) putBucketHandler(w http.ResponseWriter, req *http.Reques
log.Println(err) log.Println(err)
error := errorCodeError(InternalError) error := errorCodeError(InternalError)
errorResponse := getErrorResponse(error, bucket) errorResponse := getErrorResponse(error, bucket)
w.WriteHeader(error.HttpStatusCode) w.WriteHeader(error.HTTPStatusCode)
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) w.Write(writeErrorResponse(w, errorResponse, acceptsContentType))
} }
} }

View File

@ -38,7 +38,7 @@ type ObjectListResponse struct {
CommonPrefixes []*Prefix CommonPrefixes []*Prefix
} }
// Bucket list response format // BucketListResponse - bucket list response format
type BucketListResponse struct { type BucketListResponse struct {
XMLName xml.Name `xml:"ListAllMyBucketsResult" json:"-"` XMLName xml.Name `xml:"ListAllMyBucketsResult" json:"-"`
Owner Owner Owner Owner
@ -47,17 +47,18 @@ type BucketListResponse struct {
} // Buckets are nested } // Buckets are nested
} }
// Prefix - common prefix
type Prefix struct { type Prefix struct {
Prefix string Prefix string
} }
// Bucket struct // Bucket - bucket item
type Bucket struct { type Bucket struct {
Name string Name string
CreationDate string CreationDate string
} }
// Object struct // Item - object item
type Item struct { type Item struct {
Key string Key string
LastModified string LastModified string
@ -67,6 +68,7 @@ type Item struct {
Owner Owner Owner Owner
} }
// Owner - bucket owner/principal
type Owner struct { type Owner struct {
ID string ID string
DisplayName string DisplayName string

View File

@ -25,17 +25,17 @@ import (
type Error struct { type Error struct {
Code string Code string
Description string Description string
HttpStatusCode int HTTPStatusCode int
} }
// Error response format // ErrorResponse - error response format
type ErrorResponse struct { type ErrorResponse struct {
XMLName xml.Name `xml:"Error" json:"-"` XMLName xml.Name `xml:"Error" json:"-"`
Code string Code string
Message string Message string
Resource string Resource string
RequestId string RequestID string
HostId string HostID string
} }
// Error codes, non exhaustive list // Error codes, non exhaustive list
@ -47,7 +47,7 @@ const (
EntityTooLarge EntityTooLarge
IncompleteBody IncompleteBody
InternalError InternalError
InvalidAccessKeyId InvalidAccessKeyID
InvalidBucketName InvalidBucketName
InvalidDigest InvalidDigest
InvalidRange InvalidRange
@ -70,117 +70,117 @@ var errorCodeResponse = map[int]Error{
AccessDenied: { AccessDenied: {
Code: "AccessDenied", Code: "AccessDenied",
Description: "Access Denied", Description: "Access Denied",
HttpStatusCode: http.StatusForbidden, HTTPStatusCode: http.StatusForbidden,
}, },
BadDigest: { BadDigest: {
Code: "BadDigest", Code: "BadDigest",
Description: "The Content-MD5 you specified did not match what we received.", Description: "The Content-MD5 you specified did not match what we received.",
HttpStatusCode: http.StatusBadRequest, HTTPStatusCode: http.StatusBadRequest,
}, },
BucketAlreadyExists: { BucketAlreadyExists: {
Code: "BucketAlreadyExists", Code: "BucketAlreadyExists",
Description: "The requested bucket name is not available.", Description: "The requested bucket name is not available.",
HttpStatusCode: http.StatusConflict, HTTPStatusCode: http.StatusConflict,
}, },
EntityTooSmall: { EntityTooSmall: {
Code: "EntityTooSmall", Code: "EntityTooSmall",
Description: "Your proposed upload is smaller than the minimum allowed object size.", Description: "Your proposed upload is smaller than the minimum allowed object size.",
HttpStatusCode: http.StatusBadRequest, HTTPStatusCode: http.StatusBadRequest,
}, },
EntityTooLarge: { EntityTooLarge: {
Code: "EntityTooLarge", Code: "EntityTooLarge",
Description: "Your proposed upload exceeds the maximum allowed object size.", Description: "Your proposed upload exceeds the maximum allowed object size.",
HttpStatusCode: http.StatusBadRequest, HTTPStatusCode: http.StatusBadRequest,
}, },
IncompleteBody: { IncompleteBody: {
Code: "IncompleteBody", Code: "IncompleteBody",
Description: "You did not provide the number of bytes specified by the Content-Length HTTP header", Description: "You did not provide the number of bytes specified by the Content-Length HTTP header",
HttpStatusCode: http.StatusBadRequest, HTTPStatusCode: http.StatusBadRequest,
}, },
InternalError: { InternalError: {
Code: "InternalError", Code: "InternalError",
Description: "We encountered an internal error, please try again.", Description: "We encountered an internal error, please try again.",
HttpStatusCode: http.StatusInternalServerError, HTTPStatusCode: http.StatusInternalServerError,
}, },
InvalidAccessKeyId: { InvalidAccessKeyID: {
Code: "InvalidAccessKeyId", Code: "InvalidAccessKeyID",
Description: "The access key Id you provided does not exist in our records.", Description: "The access key ID you provided does not exist in our records.",
HttpStatusCode: http.StatusForbidden, HTTPStatusCode: http.StatusForbidden,
}, },
InvalidBucketName: { InvalidBucketName: {
Code: "InvalidBucketName", Code: "InvalidBucketName",
Description: "The specified bucket is not valid.", Description: "The specified bucket is not valid.",
HttpStatusCode: http.StatusBadRequest, HTTPStatusCode: http.StatusBadRequest,
}, },
InvalidDigest: { InvalidDigest: {
Code: "InvalidDigest", Code: "InvalidDigest",
Description: "The Content-MD5 you specified is not valid.", Description: "The Content-MD5 you specified is not valid.",
HttpStatusCode: http.StatusBadRequest, HTTPStatusCode: http.StatusBadRequest,
}, },
InvalidRange: { InvalidRange: {
Code: "InvalidRange", Code: "InvalidRange",
Description: "The requested range cannot be satisfied.", Description: "The requested range cannot be satisfied.",
HttpStatusCode: http.StatusRequestedRangeNotSatisfiable, HTTPStatusCode: http.StatusRequestedRangeNotSatisfiable,
}, },
MalformedXML: { MalformedXML: {
Code: "MalformedXML", Code: "MalformedXML",
Description: "The XML you provided was not well-formed or did not validate against our published schema.", Description: "The XML you provided was not well-formed or did not validate against our published schema.",
HttpStatusCode: http.StatusBadRequest, HTTPStatusCode: http.StatusBadRequest,
}, },
MissingContentLength: { MissingContentLength: {
Code: "MissingContentLength", Code: "MissingContentLength",
Description: "You must provide the Content-Length HTTP header.", Description: "You must provide the Content-Length HTTP header.",
HttpStatusCode: http.StatusLengthRequired, HTTPStatusCode: http.StatusLengthRequired,
}, },
MissingRequestBodyError: { MissingRequestBodyError: {
Code: "MissingRequestBodyError", Code: "MissingRequestBodyError",
Description: "Request body is empty.", Description: "Request body is empty.",
HttpStatusCode: http.StatusLengthRequired, HTTPStatusCode: http.StatusLengthRequired,
}, },
NoSuchBucket: { NoSuchBucket: {
Code: "NoSuchBucket", Code: "NoSuchBucket",
Description: "The specified bucket does not exist.", Description: "The specified bucket does not exist.",
HttpStatusCode: http.StatusNotFound, HTTPStatusCode: http.StatusNotFound,
}, },
NoSuchKey: { NoSuchKey: {
Code: "NoSuchKey", Code: "NoSuchKey",
Description: "The specified key does not exist.", Description: "The specified key does not exist.",
HttpStatusCode: http.StatusNotFound, HTTPStatusCode: http.StatusNotFound,
}, },
NoSuchUpload: { NoSuchUpload: {
Code: "NoSuchUpload", Code: "NoSuchUpload",
Description: "The specified multipart upload does not exist.", Description: "The specified multipart upload does not exist.",
HttpStatusCode: http.StatusNotFound, HTTPStatusCode: http.StatusNotFound,
}, },
NotImplemented: { NotImplemented: {
Code: "NotImplemented", Code: "NotImplemented",
Description: "A header you provided implies functionality that is not implemented.", Description: "A header you provided implies functionality that is not implemented.",
HttpStatusCode: http.StatusNotImplemented, HTTPStatusCode: http.StatusNotImplemented,
}, },
RequestTimeTooSkewed: { RequestTimeTooSkewed: {
Code: "RequestTimeTooSkewed", Code: "RequestTimeTooSkewed",
Description: "The difference between the request time and the server's time is too large.", Description: "The difference between the request time and the server's time is too large.",
HttpStatusCode: http.StatusForbidden, HTTPStatusCode: http.StatusForbidden,
}, },
SignatureDoesNotMatch: { SignatureDoesNotMatch: {
Code: "SignatureDoesNotMatch", Code: "SignatureDoesNotMatch",
Description: "The request signature we calculated does not match the signature you provided.", Description: "The request signature we calculated does not match the signature you provided.",
HttpStatusCode: http.StatusForbidden, HTTPStatusCode: http.StatusForbidden,
}, },
TooManyBuckets: { TooManyBuckets: {
Code: "TooManyBuckets", Code: "TooManyBuckets",
Description: "You have attempted to create more buckets than allowed.", Description: "You have attempted to create more buckets than allowed.",
HttpStatusCode: http.StatusBadRequest, HTTPStatusCode: http.StatusBadRequest,
}, },
InvalidPolicyDocument: { InvalidPolicyDocument: {
Code: "InvalidPolicyDocument", Code: "InvalidPolicyDocument",
Description: "The content of the form does not meet the conditions specified in the policy document.", Description: "The content of the form does not meet the conditions specified in the policy document.",
HttpStatusCode: http.StatusBadRequest, HTTPStatusCode: http.StatusBadRequest,
}, },
NoSuchBucketPolicy: { NoSuchBucketPolicy: {
Code: "NoSuchBucketPolicy", Code: "NoSuchBucketPolicy",
Description: "The specified bucket does not have a bucket policy.", Description: "The specified bucket does not have a bucket policy.",
HttpStatusCode: http.StatusNotFound, HTTPStatusCode: http.StatusNotFound,
}, },
} }
@ -199,8 +199,8 @@ func getErrorResponse(err Error, resource string) ErrorResponse {
data.Resource = resource data.Resource = resource
} }
// TODO implement this in future // TODO implement this in future
data.RequestId = "3L137" data.RequestID = "3L137"
data.HostId = "3L137" data.HostID = "3L137"
return data return data
} }

View File

@ -60,18 +60,25 @@ func (h vHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if err := h.conf.ReadConfig(); err != nil { if err := h.conf.ReadConfig(); err != nil {
error := errorCodeError(InternalError) error := errorCodeError(InternalError)
errorResponse := getErrorResponse(error, "") errorResponse := getErrorResponse(error, "")
w.WriteHeader(error.HttpStatusCode) w.WriteHeader(error.HTTPStatusCode)
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) w.Write(writeErrorResponse(w, errorResponse, acceptsContentType))
} else { } else {
user := h.conf.GetKey(accessKey) user, ok := h.conf.Users[accessKey]
ok, _ := signers.ValidateRequest(user, r) if ok == false {
if ok {
h.handler.ServeHTTP(w, r)
} else {
error := errorCodeError(AccessDenied) error := errorCodeError(AccessDenied)
errorResponse := getErrorResponse(error, "") errorResponse := getErrorResponse(error, "")
w.WriteHeader(error.HttpStatusCode) w.WriteHeader(error.HTTPStatusCode)
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) w.Write(writeErrorResponse(w, errorResponse, acceptsContentType))
} else {
ok, _ = signers.ValidateRequest(user, r)
if ok {
h.handler.ServeHTTP(w, r)
} else {
error := errorCodeError(AccessDenied)
errorResponse := getErrorResponse(error, "")
w.WriteHeader(error.HTTPStatusCode)
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType))
}
} }
} }
} else { } else {
@ -84,7 +91,7 @@ func (h vHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// ## Uncommented below links of code after disabling anonymous requests // ## Uncommented below links of code after disabling anonymous requests
// error := errorCodeError(AccessDenied) // error := errorCodeError(AccessDenied)
// errorResponse := getErrorResponse(error, "") // errorResponse := getErrorResponse(error, "")
// w.WriteHeader(error.HttpStatusCode) // w.WriteHeader(error.HTTPStatusCode)
// w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) // w.Write(writeErrorResponse(w, errorResponse, acceptsContentType))
} }
} }
@ -102,7 +109,7 @@ func (h rHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if ignoreUnImplementedObjectResources(r) || ignoreUnImplementedBucketResources(r) { if ignoreUnImplementedObjectResources(r) || ignoreUnImplementedBucketResources(r) {
error := errorCodeError(NotImplemented) error := errorCodeError(NotImplemented)
errorResponse := getErrorResponse(error, "") errorResponse := getErrorResponse(error, "")
w.WriteHeader(error.HttpStatusCode) w.WriteHeader(error.HTTPStatusCode)
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) w.Write(writeErrorResponse(w, errorResponse, acceptsContentType))
} else { } else {
h.handler.ServeHTTP(w, r) h.handler.ServeHTTP(w, r)

View File

@ -26,13 +26,13 @@ import (
) )
// private use // private use
type minioApi struct { type minioAPI struct {
domain string domain string
storage mstorage.Storage storage mstorage.Storage
} }
// Path based routing // Path based routing
func pathMux(api minioApi, mux *x.Router) *x.Router { func pathMux(api minioAPI, mux *x.Router) *x.Router {
mux.HandleFunc("/", api.listBucketsHandler).Methods("GET") mux.HandleFunc("/", api.listBucketsHandler).Methods("GET")
mux.HandleFunc("/{bucket}", api.listObjectsHandler).Methods("GET") mux.HandleFunc("/{bucket}", api.listObjectsHandler).Methods("GET")
mux.HandleFunc("/{bucket}", api.putBucketHandler).Methods("PUT") mux.HandleFunc("/{bucket}", api.putBucketHandler).Methods("PUT")
@ -44,7 +44,7 @@ func pathMux(api minioApi, mux *x.Router) *x.Router {
} }
// Domain based routing // Domain based routing
func domainMux(api minioApi, mux *x.Router) *x.Router { func domainMux(api minioAPI, mux *x.Router) *x.Router {
mux.HandleFunc("/", mux.HandleFunc("/",
api.listObjectsHandler).Host("{bucket}" + "." + api.domain).Methods("GET") api.listObjectsHandler).Host("{bucket}" + "." + api.domain).Methods("GET")
mux.HandleFunc("/{object:.*}", mux.HandleFunc("/{object:.*}",
@ -60,7 +60,7 @@ func domainMux(api minioApi, mux *x.Router) *x.Router {
} }
// Get proper router based on domain availability // Get proper router based on domain availability
func getMux(api minioApi, mux *x.Router) *x.Router { func getMux(api minioAPI, mux *x.Router) *x.Router {
switch true { switch true {
case api.domain == "": case api.domain == "":
return pathMux(api, mux) return pathMux(api, mux)
@ -71,10 +71,10 @@ func getMux(api minioApi, mux *x.Router) *x.Router {
return nil return nil
} }
// Http wrapper handler // HTTPHandler - http wrapper handler
func HttpHandler(domain string, storage mstorage.Storage) http.Handler { func HTTPHandler(domain string, storage mstorage.Storage) http.Handler {
var mux *x.Router var mux *x.Router
var api = minioApi{} var api = minioAPI{}
api.storage = storage api.storage = storage
api.domain = domain api.domain = domain

View File

@ -28,7 +28,7 @@ import (
// ---------- // ----------
// This implementation of the GET operation retrieves object. To use GET, // This implementation of the GET operation retrieves object. To use GET,
// you must have READ access to the object. // you must have READ access to the object.
func (server *minioApi) getObjectHandler(w http.ResponseWriter, req *http.Request) { func (server *minioAPI) getObjectHandler(w http.ResponseWriter, req *http.Request) {
var object, bucket string var object, bucket string
acceptsContentType := getContentType(req) acceptsContentType := getContentType(req)
@ -50,21 +50,21 @@ func (server *minioApi) getObjectHandler(w http.ResponseWriter, req *http.Reques
{ {
error := errorCodeError(NoSuchKey) error := errorCodeError(NoSuchKey)
errorResponse := getErrorResponse(error, "/"+bucket+"/"+object) errorResponse := getErrorResponse(error, "/"+bucket+"/"+object)
w.WriteHeader(error.HttpStatusCode) w.WriteHeader(error.HTTPStatusCode)
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) w.Write(writeErrorResponse(w, errorResponse, acceptsContentType))
} }
case mstorage.ObjectNameInvalid: case mstorage.ObjectNameInvalid:
{ {
error := errorCodeError(NoSuchKey) error := errorCodeError(NoSuchKey)
errorResponse := getErrorResponse(error, "/"+bucket+"/"+object) errorResponse := getErrorResponse(error, "/"+bucket+"/"+object)
w.WriteHeader(error.HttpStatusCode) w.WriteHeader(error.HTTPStatusCode)
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) w.Write(writeErrorResponse(w, errorResponse, acceptsContentType))
} }
case mstorage.BucketNameInvalid: case mstorage.BucketNameInvalid:
{ {
error := errorCodeError(InvalidBucketName) error := errorCodeError(InvalidBucketName)
errorResponse := getErrorResponse(error, "/"+bucket+"/"+object) errorResponse := getErrorResponse(error, "/"+bucket+"/"+object)
w.WriteHeader(error.HttpStatusCode) w.WriteHeader(error.HTTPStatusCode)
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) w.Write(writeErrorResponse(w, errorResponse, acceptsContentType))
} }
case mstorage.ImplementationError: case mstorage.ImplementationError:
@ -73,7 +73,7 @@ func (server *minioApi) getObjectHandler(w http.ResponseWriter, req *http.Reques
log.Println(err) log.Println(err)
error := errorCodeError(InternalError) error := errorCodeError(InternalError)
errorResponse := getErrorResponse(error, "/"+bucket+"/"+object) errorResponse := getErrorResponse(error, "/"+bucket+"/"+object)
w.WriteHeader(error.HttpStatusCode) w.WriteHeader(error.HTTPStatusCode)
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) w.Write(writeErrorResponse(w, errorResponse, acceptsContentType))
} }
} }
@ -82,7 +82,7 @@ func (server *minioApi) getObjectHandler(w http.ResponseWriter, req *http.Reques
// HEAD Object // HEAD Object
// ----------- // -----------
// The HEAD operation retrieves metadata from an object without returning the object itself. // The HEAD operation retrieves metadata from an object without returning the object itself.
func (server *minioApi) headObjectHandler(w http.ResponseWriter, req *http.Request) { func (server *minioAPI) headObjectHandler(w http.ResponseWriter, req *http.Request) {
var object, bucket string var object, bucket string
acceptsContentType := getContentType(req) acceptsContentType := getContentType(req)
vars := mux.Vars(req) vars := mux.Vars(req)
@ -97,14 +97,14 @@ func (server *minioApi) headObjectHandler(w http.ResponseWriter, req *http.Reque
{ {
error := errorCodeError(NoSuchKey) error := errorCodeError(NoSuchKey)
errorResponse := getErrorResponse(error, "/"+bucket+"/"+object) errorResponse := getErrorResponse(error, "/"+bucket+"/"+object)
w.WriteHeader(error.HttpStatusCode) w.WriteHeader(error.HTTPStatusCode)
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) w.Write(writeErrorResponse(w, errorResponse, acceptsContentType))
} }
case mstorage.ObjectNameInvalid: case mstorage.ObjectNameInvalid:
{ {
error := errorCodeError(NoSuchKey) error := errorCodeError(NoSuchKey)
errorResponse := getErrorResponse(error, "/"+bucket+"/"+object) errorResponse := getErrorResponse(error, "/"+bucket+"/"+object)
w.WriteHeader(error.HttpStatusCode) w.WriteHeader(error.HTTPStatusCode)
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) w.Write(writeErrorResponse(w, errorResponse, acceptsContentType))
} }
case mstorage.ImplementationError: case mstorage.ImplementationError:
@ -113,7 +113,7 @@ func (server *minioApi) headObjectHandler(w http.ResponseWriter, req *http.Reque
log.Println(err) log.Println(err)
error := errorCodeError(InternalError) error := errorCodeError(InternalError)
errorResponse := getErrorResponse(error, "/"+bucket+"/"+object) errorResponse := getErrorResponse(error, "/"+bucket+"/"+object)
w.WriteHeader(error.HttpStatusCode) w.WriteHeader(error.HTTPStatusCode)
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) w.Write(writeErrorResponse(w, errorResponse, acceptsContentType))
} }
} }
@ -122,7 +122,7 @@ func (server *minioApi) headObjectHandler(w http.ResponseWriter, req *http.Reque
// PUT Object // PUT Object
// ---------- // ----------
// This implementation of the PUT operation adds an object to a bucket. // This implementation of the PUT operation adds an object to a bucket.
func (server *minioApi) putObjectHandler(w http.ResponseWriter, req *http.Request) { func (server *minioAPI) putObjectHandler(w http.ResponseWriter, req *http.Request) {
var object, bucket string var object, bucket string
vars := mux.Vars(req) vars := mux.Vars(req)
acceptsContentType := getContentType(req) acceptsContentType := getContentType(req)
@ -146,28 +146,28 @@ func (server *minioApi) putObjectHandler(w http.ResponseWriter, req *http.Reques
log.Println(err) log.Println(err)
error := errorCodeError(InternalError) error := errorCodeError(InternalError)
errorResponse := getErrorResponse(error, "/"+bucket+"/"+object) errorResponse := getErrorResponse(error, "/"+bucket+"/"+object)
w.WriteHeader(error.HttpStatusCode) w.WriteHeader(error.HTTPStatusCode)
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) w.Write(writeErrorResponse(w, errorResponse, acceptsContentType))
} }
case mstorage.BucketNotFound: case mstorage.BucketNotFound:
{ {
error := errorCodeError(NoSuchBucket) error := errorCodeError(NoSuchBucket)
errorResponse := getErrorResponse(error, "/"+bucket+"/"+object) errorResponse := getErrorResponse(error, "/"+bucket+"/"+object)
w.WriteHeader(error.HttpStatusCode) w.WriteHeader(error.HTTPStatusCode)
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) w.Write(writeErrorResponse(w, errorResponse, acceptsContentType))
} }
case mstorage.BucketNameInvalid: case mstorage.BucketNameInvalid:
{ {
error := errorCodeError(InvalidBucketName) error := errorCodeError(InvalidBucketName)
errorResponse := getErrorResponse(error, "/"+bucket+"/"+object) errorResponse := getErrorResponse(error, "/"+bucket+"/"+object)
w.WriteHeader(error.HttpStatusCode) w.WriteHeader(error.HTTPStatusCode)
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) w.Write(writeErrorResponse(w, errorResponse, acceptsContentType))
} }
case mstorage.ObjectExists: case mstorage.ObjectExists:
{ {
error := errorCodeError(NotImplemented) error := errorCodeError(NotImplemented)
errorResponse := getErrorResponse(error, "/"+bucket+"/"+object) errorResponse := getErrorResponse(error, "/"+bucket+"/"+object)
w.WriteHeader(error.HttpStatusCode) w.WriteHeader(error.HTTPStatusCode)
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) w.Write(writeErrorResponse(w, errorResponse, acceptsContentType))
} }
} }

View File

@ -30,7 +30,7 @@ import (
// ----------------- // -----------------
// This implementation of the PUT operation uses the policy subresource // This implementation of the PUT operation uses the policy subresource
// to add to or replace a policy on a bucket // to add to or replace a policy on a bucket
func (server *minioApi) putBucketPolicyHandler(w http.ResponseWriter, req *http.Request) { func (server *minioAPI) putBucketPolicyHandler(w http.ResponseWriter, req *http.Request) {
vars := mux.Vars(req) vars := mux.Vars(req)
bucket := vars["bucket"] bucket := vars["bucket"]
acceptsContentType := getContentType(req) acceptsContentType := getContentType(req)
@ -39,7 +39,7 @@ func (server *minioApi) putBucketPolicyHandler(w http.ResponseWriter, req *http.
if ok == false { if ok == false {
error := errorCodeError(InvalidPolicyDocument) error := errorCodeError(InvalidPolicyDocument)
errorResponse := getErrorResponse(error, bucket) errorResponse := getErrorResponse(error, bucket)
w.WriteHeader(error.HttpStatusCode) w.WriteHeader(error.HTTPStatusCode)
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) w.Write(writeErrorResponse(w, errorResponse, acceptsContentType))
return return
} }
@ -56,14 +56,14 @@ func (server *minioApi) putBucketPolicyHandler(w http.ResponseWriter, req *http.
{ {
error := errorCodeError(InvalidBucketName) error := errorCodeError(InvalidBucketName)
errorResponse := getErrorResponse(error, bucket) errorResponse := getErrorResponse(error, bucket)
w.WriteHeader(error.HttpStatusCode) w.WriteHeader(error.HTTPStatusCode)
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) w.Write(writeErrorResponse(w, errorResponse, acceptsContentType))
} }
case mstorage.BucketNotFound: case mstorage.BucketNotFound:
{ {
error := errorCodeError(NoSuchBucket) error := errorCodeError(NoSuchBucket)
errorResponse := getErrorResponse(error, bucket) errorResponse := getErrorResponse(error, bucket)
w.WriteHeader(error.HttpStatusCode) w.WriteHeader(error.HTTPStatusCode)
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) w.Write(writeErrorResponse(w, errorResponse, acceptsContentType))
} }
case mstorage.BackendCorrupted: case mstorage.BackendCorrupted:
@ -72,7 +72,7 @@ func (server *minioApi) putBucketPolicyHandler(w http.ResponseWriter, req *http.
log.Println(err) log.Println(err)
error := errorCodeError(InternalError) error := errorCodeError(InternalError)
errorResponse := getErrorResponse(error, bucket) errorResponse := getErrorResponse(error, bucket)
w.WriteHeader(error.HttpStatusCode) w.WriteHeader(error.HTTPStatusCode)
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) w.Write(writeErrorResponse(w, errorResponse, acceptsContentType))
} }
} }
@ -82,7 +82,7 @@ func (server *minioApi) putBucketPolicyHandler(w http.ResponseWriter, req *http.
// ----------------- // -----------------
// This implementation of the GET operation uses the policy subresource // This implementation of the GET operation uses the policy subresource
// to return the policy of a specified bucket. // to return the policy of a specified bucket.
func (server *minioApi) getBucketPolicyHandler(w http.ResponseWriter, req *http.Request) { func (server *minioAPI) getBucketPolicyHandler(w http.ResponseWriter, req *http.Request) {
vars := mux.Vars(req) vars := mux.Vars(req)
bucket := vars["bucket"] bucket := vars["bucket"]
acceptsContentType := getContentType(req) acceptsContentType := getContentType(req)
@ -95,7 +95,7 @@ func (server *minioApi) getBucketPolicyHandler(w http.ResponseWriter, req *http.
if ret != nil { if ret != nil {
error := errorCodeError(InternalError) error := errorCodeError(InternalError)
errorResponse := getErrorResponse(error, bucket) errorResponse := getErrorResponse(error, bucket)
w.WriteHeader(error.HttpStatusCode) w.WriteHeader(error.HTTPStatusCode)
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) w.Write(writeErrorResponse(w, errorResponse, acceptsContentType))
} }
writeCommonHeaders(w, getContentString(acceptsContentType)) writeCommonHeaders(w, getContentString(acceptsContentType))
@ -106,21 +106,21 @@ func (server *minioApi) getBucketPolicyHandler(w http.ResponseWriter, req *http.
{ {
error := errorCodeError(InvalidBucketName) error := errorCodeError(InvalidBucketName)
errorResponse := getErrorResponse(error, bucket) errorResponse := getErrorResponse(error, bucket)
w.WriteHeader(error.HttpStatusCode) w.WriteHeader(error.HTTPStatusCode)
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) w.Write(writeErrorResponse(w, errorResponse, acceptsContentType))
} }
case mstorage.BucketNotFound: case mstorage.BucketNotFound:
{ {
error := errorCodeError(NoSuchBucket) error := errorCodeError(NoSuchBucket)
errorResponse := getErrorResponse(error, bucket) errorResponse := getErrorResponse(error, bucket)
w.WriteHeader(error.HttpStatusCode) w.WriteHeader(error.HTTPStatusCode)
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) w.Write(writeErrorResponse(w, errorResponse, acceptsContentType))
} }
case mstorage.BucketPolicyNotFound: case mstorage.BucketPolicyNotFound:
{ {
error := errorCodeError(NoSuchBucketPolicy) error := errorCodeError(NoSuchBucketPolicy)
errorResponse := getErrorResponse(error, bucket) errorResponse := getErrorResponse(error, bucket)
w.WriteHeader(error.HttpStatusCode) w.WriteHeader(error.HTTPStatusCode)
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) w.Write(writeErrorResponse(w, errorResponse, acceptsContentType))
} }
case mstorage.BackendCorrupted: case mstorage.BackendCorrupted:
@ -129,7 +129,7 @@ func (server *minioApi) getBucketPolicyHandler(w http.ResponseWriter, req *http.
log.Println(err) log.Println(err)
error := errorCodeError(InternalError) error := errorCodeError(InternalError)
errorResponse := getErrorResponse(error, bucket) errorResponse := getErrorResponse(error, bucket)
w.WriteHeader(error.HttpStatusCode) w.WriteHeader(error.HTTPStatusCode)
w.Write(writeErrorResponse(w, errorResponse, acceptsContentType)) w.Write(writeErrorResponse(w, errorResponse, acceptsContentType))
} }
} }

View File

@ -54,16 +54,16 @@ func generateBucketsListResult(buckets []mstorage.BucketMetadata) BucketListResp
return data return data
} }
type ItemKey []*Item type itemKey []*Item
// Len // Len
func (b ItemKey) Len() int { return len(b) } func (b itemKey) Len() int { return len(b) }
// Swap // Swap
func (b ItemKey) Swap(i, j int) { b[i], b[j] = b[j], b[i] } func (b itemKey) Swap(i, j int) { b[i], b[j] = b[j], b[i] }
// Less // Less
func (b ItemKey) Less(i, j int) bool { return b[i].Key < b[j].Key } 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 // takes a set of objects and prepares the objects for serialization
// input: // input:
@ -95,7 +95,7 @@ func generateObjectsListResult(bucket string, objects []mstorage.ObjectMetadata,
content.Owner = owner content.Owner = owner
contents = append(contents, content) contents = append(contents, content)
} }
sort.Sort(ItemKey(contents)) sort.Sort(itemKey(contents))
data.Name = bucket data.Name = bucket
data.Contents = contents data.Contents = contents
data.MaxKeys = bucketResources.Maxkeys data.MaxKeys = bucketResources.Maxkeys

View File

@ -29,10 +29,10 @@ import (
) )
const ( const (
DEFAULT_WEB = "polygon" defaultWeb = "polygon"
) )
type webUiApi struct { type webAPI struct {
conf config.Config conf config.Config
webPath string webPath string
} }
@ -42,16 +42,16 @@ type encoder interface {
Encode(v interface{}) error Encode(v interface{}) error
} }
// Http wrapper handler // HTTPHandler - http wrapper handler
func HttpHandler() http.Handler { func HTTPHandler() http.Handler {
mux := mux.NewRouter() mux := mux.NewRouter()
var api = webUiApi{} var api = webAPI{}
if err := api.conf.SetupConfig(); err != nil { if err := api.conf.SetupConfig(); err != nil {
log.Fatal(err) log.Fatal(err)
} }
api.webPath = path.Join(api.conf.GetConfigPath(), DEFAULT_WEB) api.webPath = path.Join(api.conf.GetConfigPath(), defaultWeb)
mux.Handle("/{polygon:.*}", http.FileServer(http.Dir(api.webPath))).Methods("GET") mux.Handle("/{polygon:.*}", http.FileServer(http.Dir(api.webPath))).Methods("GET")
mux.HandleFunc("/access", api.accessHandler).Methods("POST") mux.HandleFunc("/access", api.accessHandler).Methods("POST")
return mux return mux
@ -68,7 +68,7 @@ func writeResponse(w http.ResponseWriter, response interface{}) []byte {
return bytesBuffer.Bytes() return bytesBuffer.Bytes()
} }
func (web *webUiApi) accessHandler(w http.ResponseWriter, req *http.Request) { func (web *webAPI) accessHandler(w http.ResponseWriter, req *http.Request) {
var err error var err error
var accesskey, secretkey []byte var accesskey, secretkey []byte
username := req.FormValue("username") username := req.FormValue("username")
@ -92,7 +92,7 @@ func (web *webUiApi) accessHandler(w http.ResponseWriter, req *http.Request) {
var user = config.User{} var user = config.User{}
user.Name = username user.Name = username
accesskey, err = keys.GetRandomAlphaNumeric(keys.MINIO_ACCESS_ID) accesskey, err = keys.GenerateRandomAlphaNumeric(keys.MinioAccessID)
if err != nil { if err != nil {
w.WriteHeader(http.StatusInternalServerError) w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(err.Error())) w.Write([]byte(err.Error()))
@ -100,7 +100,7 @@ func (web *webUiApi) accessHandler(w http.ResponseWriter, req *http.Request) {
} }
user.AccessKey = string(accesskey) user.AccessKey = string(accesskey)
secretkey, err = keys.GetRandomBase64(keys.MINIO_SECRET_ID) secretkey, err = keys.GenerateRandomBase64(keys.MinioSecretID)
if err != nil { if err != nil {
w.WriteHeader(http.StatusInternalServerError) w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(err.Error())) w.Write([]byte(err.Error()))

View File

@ -19,30 +19,31 @@ package httpserver
import ( import (
"log" "log"
"net/http" "net/http"
// "time"
) )
type HttpServerConfig struct { // Config - http server config
type Config struct {
Address string Address string
TLS bool TLS bool
CertFile string CertFile string
KeyFile string KeyFile string
Websocket bool // implement it - TODO Websocket bool // TODO
} }
type HttpServer struct{} // Server - http server related
type Server struct{}
// Start http server // Start http server
func Start(handler http.Handler, config HttpServerConfig) (chan<- string, <-chan error, *HttpServer) { func Start(handler http.Handler, config Config) (chan<- string, <-chan error, *Server) {
ctrlChannel := make(chan string) ctrlChannel := make(chan string)
errorChannel := make(chan error) errorChannel := make(chan error)
server := HttpServer{} server := Server{}
go start(ctrlChannel, errorChannel, handler, config, &server) go start(ctrlChannel, errorChannel, handler, config, &server)
return ctrlChannel, errorChannel, &server return ctrlChannel, errorChannel, &server
} }
func start(ctrlChannel <-chan string, errorChannel chan<- error, func start(ctrlChannel <-chan string, errorChannel chan<- error,
router http.Handler, config HttpServerConfig, server *HttpServer) { router http.Handler, config Config, server *Server) {
var err error var err error
// Minio server config // Minio server config

View File

@ -30,45 +30,51 @@ import (
"github.com/minio-io/minio/pkg/storage/inmemory" "github.com/minio-io/minio/pkg/storage/inmemory"
) )
type ServerConfig struct { // Config - http server parameters
type Config struct {
Domain string Domain string
Address string Address string
Tls bool TLS bool
CertFile string CertFile string
KeyFile string KeyFile string
ApiType interface{} APIType interface{}
} }
type MinioApi struct { // MinioAPI - storage type donut, fs, inmemory
type MinioAPI struct {
StorageType StorageType StorageType StorageType
} }
type WebUIApi struct { // WebAPI - webui related
Websocket bool type WebAPI struct {
Websocket bool // TODO
} }
// StorageType - different storage types supported by minio
type StorageType int type StorageType int
// Storage types
const ( const (
InMemoryStorage = iota InMemory = iota
FileStorage File
Donut
) )
func getHttpChannels(configs []ServerConfig) (ctrlChans []chan<- string, statusChans []<-chan error) { func getHTTPChannels(configs []Config) (ctrlChans []chan<- string, statusChans []<-chan error) {
// a pair of control channels, we use these primarily to add to the lists above // a pair of control channels, we use these primarily to add to the lists above
var ctrlChan chan<- string var ctrlChan chan<- string
var statusChan <-chan error var statusChan <-chan error
for _, config := range configs { for _, config := range configs {
switch k := config.ApiType.(type) { switch k := config.APIType.(type) {
case MinioApi: case MinioAPI:
{ {
// configure web server // configure web server
var storage mstorage.Storage var storage mstorage.Storage
var httpConfig = httpserver.HttpServerConfig{} var httpConfig = httpserver.Config{}
httpConfig.Address = config.Address httpConfig.Address = config.Address
httpConfig.Websocket = false httpConfig.Websocket = false
httpConfig.TLS = config.Tls httpConfig.TLS = config.TLS
if config.CertFile != "" { if config.CertFile != "" {
httpConfig.CertFile = config.CertFile httpConfig.CertFile = config.CertFile
@ -79,22 +85,22 @@ func getHttpChannels(configs []ServerConfig) (ctrlChans []chan<- string, statusC
ctrlChans, statusChans, storage = getStorageChannels(k.StorageType) ctrlChans, statusChans, storage = getStorageChannels(k.StorageType)
// start minio api in a web server, pass storage driver into it // start minio api in a web server, pass storage driver into it
ctrlChan, statusChan, _ = httpserver.Start(minioapi.HttpHandler(config.Domain, storage), httpConfig) ctrlChan, statusChan, _ = httpserver.Start(minioapi.HTTPHandler(config.Domain, storage), httpConfig)
ctrlChans = append(ctrlChans, ctrlChan) ctrlChans = append(ctrlChans, ctrlChan)
statusChans = append(statusChans, statusChan) statusChans = append(statusChans, statusChan)
} }
case WebUIApi: case WebAPI:
{ {
var httpConfig = httpserver.HttpServerConfig{} var httpConfig = httpserver.Config{}
httpConfig.Address = config.Address httpConfig.Address = config.Address
httpConfig.TLS = config.Tls httpConfig.TLS = config.TLS
httpConfig.CertFile = config.CertFile httpConfig.CertFile = config.CertFile
httpConfig.KeyFile = config.KeyFile httpConfig.KeyFile = config.KeyFile
httpConfig.Websocket = k.Websocket httpConfig.Websocket = k.Websocket
ctrlChan, statusChan, _ = httpserver.Start(webuiapi.HttpHandler(), httpConfig) ctrlChan, statusChan, _ = httpserver.Start(webuiapi.HTTPHandler(), httpConfig)
ctrlChans = append(ctrlChans, ctrlChan) ctrlChans = append(ctrlChans, ctrlChan)
statusChans = append(statusChans, statusChan) statusChans = append(statusChans, statusChan)
@ -120,13 +126,13 @@ func getStorageChannels(storageType StorageType) (ctrlChans []chan<- string, sta
// - ctrlChans has channel to communicate to storage // - ctrlChans has channel to communicate to storage
// - statusChans has channel for messages coming from storage // - statusChans has channel for messages coming from storage
switch { switch {
case storageType == InMemoryStorage: case storageType == InMemory:
{ {
ctrlChan, statusChan, storage = inmemory.Start() ctrlChan, statusChan, storage = inmemory.Start()
ctrlChans = append(ctrlChans, ctrlChan) ctrlChans = append(ctrlChans, ctrlChan)
statusChans = append(statusChans, statusChan) statusChans = append(statusChans, statusChan)
} }
case storageType == FileStorage: case storageType == File:
{ {
u, err := user.Current() u, err := user.Current()
if err != nil { if err != nil {
@ -143,10 +149,10 @@ func getStorageChannels(storageType StorageType) (ctrlChans []chan<- string, sta
return return
} }
// Create channels // Start - create channels
func Start(configs []ServerConfig) { func Start(configs []Config) {
// reflected looping is necessary to remove dead channels from loop and not flood switch // reflected looping is necessary to remove dead channels from loop and not flood switch
ctrlChans, statusChans := getHttpChannels(configs) ctrlChans, statusChans := getHTTPChannels(configs)
cases := createSelectCases(statusChans) cases := createSelectCases(statusChans)
for len(cases) > 0 { for len(cases) > 0 {
chosen, value, recvOk := reflect.Select(cases) chosen, value, recvOk := reflect.Select(cases)

View File

@ -24,8 +24,10 @@ import (
"io" "io"
) )
// Metadata map
type Metadata map[string]string type Metadata map[string]string
// DataHeader struct
type DataHeader struct { type DataHeader struct {
Key string Key string
Part uint8 Part uint8
@ -33,13 +35,16 @@ type DataHeader struct {
EncoderParams EncoderParams EncoderParams EncoderParams
} }
// EncoderTechnique type
type EncoderTechnique int type EncoderTechnique int
// EncoderTechniques
const ( const (
Vandermonde EncoderTechnique = iota Vandermonde EncoderTechnique = iota
Cauchy Cauchy
) )
// EncoderParams struct
type EncoderParams struct { type EncoderParams struct {
Length uint32 Length uint32
K uint8 K uint8
@ -47,7 +52,7 @@ type EncoderParams struct {
Technique EncoderTechnique Technique EncoderTechnique
} }
// populate new header // NewHeader populate new header
func NewHeader(key string, part uint8, metadata Metadata, encoderParams EncoderParams) DataHeader { func NewHeader(key string, part uint8, metadata Metadata, encoderParams EncoderParams) DataHeader {
header := DataHeader{} header := DataHeader{}
header.Key = key header.Key = key
@ -62,7 +67,7 @@ func NewHeader(key string, part uint8, metadata Metadata, encoderParams EncoderP
return header return header
} }
// validate populated header // ValidateHeader validate populated header
func ValidateHeader(header DataHeader) bool { func ValidateHeader(header DataHeader) bool {
if header.Key == "" || header.Part < 0 || len(header.Metadata) < 2 { if header.Key == "" || header.Part < 0 || len(header.Metadata) < 2 {
return false return false
@ -75,7 +80,7 @@ func ValidateHeader(header DataHeader) bool {
return true return true
} }
// Write data, returns error upon any failure // WriteData write data, returns error upon any failure
func WriteData(target io.Writer, header DataHeader, data io.Reader) error { func WriteData(target io.Writer, header DataHeader, data io.Reader) error {
if !ValidateHeader(header) { if !ValidateHeader(header) {
return fmt.Errorf("Invalid header") return fmt.Errorf("Invalid header")

View File

@ -44,30 +44,49 @@ import (
*/ */
// Magic list
var ( var (
MagicMINI = binary.LittleEndian.Uint32([]byte{'M', 'I', 'N', 'I'}) MagicMINI = binary.LittleEndian.Uint32([]byte{'M', 'I', 'N', 'I'})
MagicDATA = binary.LittleEndian.Uint32([]byte{'D', 'A', 'T', 'A'}) MagicDATA = binary.LittleEndian.Uint32([]byte{'D', 'A', 'T', 'A'})
MagicINIM = binary.LittleEndian.Uint32([]byte{'I', 'N', 'I', 'M'}) MagicINIM = binary.LittleEndian.Uint32([]byte{'I', 'N', 'I', 'M'})
) )
// DonutFrameHeader -
// --------------
// BlockStart uint32
// VersionMajor uint32
// Reserved uint64
// DataLen uint64
// --------------
type DonutFrameHeader struct { type DonutFrameHeader struct {
MagicMINI uint32 MagicMINI uint32
Version uint32 Version uint32
Reserved uint64 Reserved uint64
DataLength uint64 DataLength uint64
} }
// Crc32c checksum
type Crc32c uint32 type Crc32c uint32
// Sha512 checksum
type Sha512 [sha512.Size]byte type Sha512 [sha512.Size]byte
// DonutFrameFooter -
// --------------
// DataSha512 [64]byte
// BlockLen uint64
// BlockEnd uint32
// --------------
type DonutFrameFooter struct { type DonutFrameFooter struct {
DataSha512 Sha512 DataSha512 Sha512
OffsetToMINI uint64 OffsetToMINI uint64
MagicINIM uint32 MagicINIM uint32
} }
// Data buffer
type Data bytes.Buffer type Data bytes.Buffer
// Write Donut format to input io.Writer, returns error upon any failure // WriteFrame - write donut format to input io.Writer, returns error upon any failure
func WriteFrame(target io.Writer, reader io.Reader, length uint64) error { func WriteFrame(target io.Writer, reader io.Reader, length uint64) error {
// write header // write header
header := DonutFrameHeader{ header := DonutFrameHeader{

View File

@ -43,10 +43,10 @@ func (s *MySuite) TestCauchyDecode(c *C) {
chunks[9] = nil chunks[9] = nil
chunks[13] = nil chunks[13] = nil
recovered_data, err := e.Decode(chunks, length) recoveredData, err := e.Decode(chunks, length)
c.Assert(err, IsNil) c.Assert(err, IsNil)
if !bytes.Equal(data, recovered_data) { if !bytes.Equal(data, recoveredData) {
c.Fatalf("Recovered data mismatches with original data") c.Fatalf("Recovered data mismatches with original data")
} }
} }

View File

@ -38,10 +38,10 @@ func (s *MySuite) TestVanderMondeDecode(c *C) {
chunks[9] = nil chunks[9] = nil
chunks[13] = nil chunks[13] = nil
recovered_data, err := e.Decode(chunks, length) recoveredData, err := e.Decode(chunks, length)
c.Assert(err, IsNil) c.Assert(err, IsNil)
if !bytes.Equal(recovered_data, data) { if !bytes.Equal(recoveredData, data) {
c.Fatalf("Recovered data mismatches with original data") c.Fatalf("Recovered data mismatches with original data")
} }
} }

View File

@ -38,6 +38,7 @@ type storage struct {
lock *sync.Mutex lock *sync.Mutex
} }
// SerializedMetadata - carries content type
type SerializedMetadata struct { type SerializedMetadata struct {
ContentType string ContentType string
} }
@ -237,9 +238,8 @@ func (storage *storage) CopyObjectToWriter(w io.Writer, bucket string, object st
{ {
if os.IsNotExist(err) { if os.IsNotExist(err) {
return 0, mstorage.ObjectNotFound{Bucket: bucket, Object: object} return 0, mstorage.ObjectNotFound{Bucket: bucket, Object: object}
} else {
return 0, mstorage.EmbedError(bucket, object, err)
} }
return 0, mstorage.EmbedError(bucket, object, err)
} }
} }
file, err := os.Open(objectPath) file, err := os.Open(objectPath)
@ -311,20 +311,20 @@ func (storage *storage) GetObjectMetadata(bucket string, object string) (mstorag
return metadata, nil return metadata, nil
} }
type Path struct { type bucketDir struct {
files map[string]os.FileInfo files map[string]os.FileInfo
root string root string
} }
func (p *Path) getAllFiles(path string, fl os.FileInfo, err error) error { func (p *bucketDir) getAllFiles(object string, fl os.FileInfo, err error) error {
if err != nil { if err != nil {
return err return err
} }
if fl.Mode().IsRegular() { if fl.Mode().IsRegular() {
if strings.HasSuffix(path, "$metadata") { if strings.HasSuffix(object, "$metadata") {
return nil return nil
} }
_p := strings.Split(path, p.root+"/") _p := strings.Split(object, p.root+"/")
if len(_p) > 1 { if len(_p) > 1 {
p.files[_p[1]] = fl p.files[_p[1]] = fl
} }
@ -332,8 +332,8 @@ func (p *Path) getAllFiles(path string, fl os.FileInfo, err error) error {
return nil return nil
} }
func delimiter(path, delimiter string) string { func delimiter(object, delimiter string) string {
readBuffer := bytes.NewBufferString(path) readBuffer := bytes.NewBufferString(object)
reader := bufio.NewReader(readBuffer) reader := bufio.NewReader(readBuffer)
stringReader := strings.NewReader(delimiter) stringReader := strings.NewReader(delimiter)
delimited, _ := stringReader.ReadByte() delimited, _ := stringReader.ReadByte()
@ -341,20 +341,20 @@ func delimiter(path, delimiter string) string {
return delimitedStr return delimitedStr
} }
type ByObjectKey []mstorage.ObjectMetadata type byObjectKey []mstorage.ObjectMetadata
// Len // Len
func (b ByObjectKey) Len() int { return len(b) } func (b byObjectKey) Len() int { return len(b) }
// Swap // Swap
func (b ByObjectKey) Swap(i, j int) { b[i], b[j] = b[j], b[i] } func (b byObjectKey) Swap(i, j int) { b[i], b[j] = b[j], b[i] }
// Less // Less
func (b ByObjectKey) Less(i, j int) bool { return b[i].Key < b[j].Key } func (b byObjectKey) Less(i, j int) bool { return b[i].Key < b[j].Key }
// GET bucket (list objects) // GET bucket (list objects)
func (storage *storage) ListObjects(bucket string, resources mstorage.BucketResourcesMetadata) ([]mstorage.ObjectMetadata, mstorage.BucketResourcesMetadata, error) { func (storage *storage) ListObjects(bucket string, resources mstorage.BucketResourcesMetadata) ([]mstorage.ObjectMetadata, mstorage.BucketResourcesMetadata, error) {
p := Path{} p := bucketDir{}
p.files = make(map[string]os.FileInfo) p.files = make(map[string]os.FileInfo)
if mstorage.IsValidBucket(bucket) == false { if mstorage.IsValidBucket(bucket) == false {
@ -450,7 +450,7 @@ func (storage *storage) ListObjects(bucket string, resources mstorage.BucketReso
} }
ret: ret:
sort.Sort(ByObjectKey(metadataList)) sort.Sort(byObjectKey(metadataList))
return metadataList, resources, nil return metadataList, resources, nil
} }
@ -495,7 +495,7 @@ func (storage *storage) StoreObject(bucket, key, contentType string, data io.Rea
if _, err := os.Stat(objectPath); !os.IsNotExist(err) { if _, err := os.Stat(objectPath); !os.IsNotExist(err) {
return mstorage.ObjectExists{ return mstorage.ObjectExists{
Bucket: bucket, Bucket: bucket,
Key: key, Object: key,
} }
} }

View File

@ -1,5 +1,5 @@
/* /*
* Mini Object Storage, (C) 2015 Minio, Inc. * Minio Object Storage, (C) 2015 Minio, Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -72,19 +72,18 @@ func (storage *storage) CopyObjectToWriter(w io.Writer, bucket string, object st
objectBuffer := bytes.NewBuffer(val.data) objectBuffer := bytes.NewBuffer(val.data)
written, err := io.Copy(w, objectBuffer) written, err := io.Copy(w, objectBuffer)
return written, err return written, err
} else {
return 0, mstorage.ObjectNotFound{Bucket: bucket, Object: object}
} }
return 0, mstorage.ObjectNotFound{Bucket: bucket, Object: object}
} }
// Not implemented // Not implemented
func (storage *storage) StoreBucketPolicy(bucket string, policy interface{}) error { func (storage *storage) StoreBucketPolicy(bucket string, policy interface{}) error {
return mstorage.ApiNotImplemented{Api: "PutBucketPolicy"} return mstorage.APINotImplemented{API: "PutBucketPolicy"}
} }
// Not implemented // Not implemented
func (storage *storage) GetBucketPolicy(bucket string) (interface{}, error) { func (storage *storage) GetBucketPolicy(bucket string) (interface{}, error) {
return policy.BucketPolicy{}, mstorage.ApiNotImplemented{Api: "GetBucketPolicy"} return policy.BucketPolicy{}, mstorage.APINotImplemented{API: "GetBucketPolicy"}
} }
// PUT object to memory buffer // PUT object to memory buffer
@ -99,7 +98,7 @@ func (storage *storage) StoreObject(bucket, key, contentType string, data io.Rea
} }
if _, ok := storage.objectdata[objectKey]; ok == true { if _, ok := storage.objectdata[objectKey]; ok == true {
return mstorage.ObjectExists{Bucket: bucket, Key: key} return mstorage.ObjectExists{Bucket: bucket, Object: key}
} }
if contentType == "" { if contentType == "" {
@ -176,16 +175,16 @@ func (storage *storage) ListObjects(bucket string, resources mstorage.BucketReso
return results, resources, nil return results, resources, nil
} }
type ByBucketName []mstorage.BucketMetadata type byBucketName []mstorage.BucketMetadata
// Len of bucket name // Len of bucket name
func (b ByBucketName) Len() int { return len(b) } func (b byBucketName) Len() int { return len(b) }
// Swap bucket i, j // Swap bucket i, j
func (b ByBucketName) Swap(i, j int) { b[i], b[j] = b[j], b[i] } func (b byBucketName) Swap(i, j int) { b[i], b[j] = b[j], b[i] }
// Less // Less
func (b ByBucketName) Less(i, j int) bool { return b[i].Name < b[j].Name } func (b byBucketName) Less(i, j int) bool { return b[i].Name < b[j].Name }
// List buckets // List buckets
func (storage *storage) ListBuckets() ([]mstorage.BucketMetadata, error) { func (storage *storage) ListBuckets() ([]mstorage.BucketMetadata, error) {
@ -193,7 +192,7 @@ func (storage *storage) ListBuckets() ([]mstorage.BucketMetadata, error) {
for _, bucket := range storage.bucketdata { for _, bucket := range storage.bucketdata {
results = append(results, bucket.metadata) results = append(results, bucket.metadata)
} }
sort.Sort(ByBucketName(results)) sort.Sort(byBucketName(results))
return results, nil return results, nil
} }
@ -203,7 +202,6 @@ func (storage *storage) GetObjectMetadata(bucket, key string) (mstorage.ObjectMe
if object, ok := storage.objectdata[objectKey]; ok == true { if object, ok := storage.objectdata[objectKey]; ok == true {
return object.metadata, nil return object.metadata, nil
} else {
return mstorage.ObjectMetadata{}, mstorage.ObjectNotFound{Bucket: bucket, Object: key}
} }
return mstorage.ObjectMetadata{}, mstorage.ObjectNotFound{Bucket: bucket, Object: key}
} }

View File

@ -23,6 +23,7 @@ import (
"unicode/utf8" "unicode/utf8"
) )
// Storage - generic API interface
type Storage interface { type Storage interface {
// Bucket Operations // Bucket Operations
ListBuckets() ([]BucketMetadata, error) ListBuckets() ([]BucketMetadata, error)
@ -37,11 +38,13 @@ type Storage interface {
StoreObject(bucket string, key string, contentType string, data io.Reader) error StoreObject(bucket string, key string, contentType string, data io.Reader) error
} }
// BucketMetadata - name and create date
type BucketMetadata struct { type BucketMetadata struct {
Name string Name string
Created time.Time Created time.Time
} }
// ObjectMetadata - object key and its relevant metadata
type ObjectMetadata struct { type ObjectMetadata struct {
Bucket string Bucket string
Key string Key string
@ -52,7 +55,7 @@ type ObjectMetadata struct {
Size int64 Size int64
} }
// Various types of bucket resources // BucketResourcesMetadata - various types of bucket resources
type BucketResourcesMetadata struct { type BucketResourcesMetadata struct {
Prefix string Prefix string
Marker string Marker string
@ -67,7 +70,8 @@ type BucketResourcesMetadata struct {
Notification string Notification string
} }
// Verify Bucket name in accordance with http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingBucket.html // IsValidBucket - verify bucket name in accordance with
// - http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingBucket.html
func IsValidBucket(bucket string) bool { func IsValidBucket(bucket string) bool {
if len(bucket) < 3 || len(bucket) > 63 { if len(bucket) < 3 || len(bucket) > 63 {
return false return false
@ -83,7 +87,8 @@ func IsValidBucket(bucket string) bool {
return match return match
} }
// Verify Object name in accordance with http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMetadata.html // IsValidObject - verify object name in accordance with
// - http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMetadata.html
func IsValidObject(object string) bool { func IsValidObject(object string) bool {
if len(object) > 1024 || len(object) == 0 { if len(object) > 1024 || len(object) == 0 {
return false return false

View File

@ -24,7 +24,7 @@ import (
. "gopkg.in/check.v1" . "gopkg.in/check.v1"
) )
// API test suite // APITestSuite - collection of API tests
func APITestSuite(c *C, create func() Storage) { func APITestSuite(c *C, create func() Storage) {
testCreateBucket(c, create) testCreateBucket(c, create)
testMultipleObjectCreation(c, create) testMultipleObjectCreation(c, create)

View File

@ -16,62 +16,76 @@
package storage package storage
// BackendError - generic disk backend error
type BackendError struct { type BackendError struct {
Path string Path string
} }
type GenericError struct { // BackendCorrupted - path has corrupted data
Bucket string type BackendCorrupted BackendError
Path string
// APINotImplemented - generic API not implemented error
type APINotImplemented struct {
API string
} }
type ObjectExists struct { // GenericBucketError - generic bucket error
Bucket string
Key string
}
type ApiNotImplemented struct {
Api string
}
type ObjectNotFound GenericObjectError
type GenericBucketError struct { type GenericBucketError struct {
Bucket string Bucket string
} }
// GenericObjectError - generic object error
type GenericObjectError struct { type GenericObjectError struct {
Bucket string Bucket string
Object string Object string
} }
// ImplementationError - generic implementation error
type ImplementationError struct { type ImplementationError struct {
Bucket string Bucket string
Object string Object string
Err error Err error
} }
type BackendCorrupted BackendError /// Bucket related errors
// BucketPolicyNotFound - missing bucket policy
type BucketPolicyNotFound GenericBucketError type BucketPolicyNotFound GenericBucketError
// BucketNameInvalid - bucketname provided is invalid
type BucketNameInvalid GenericBucketError type BucketNameInvalid GenericBucketError
// BucketExists - bucket already exists
type BucketExists GenericBucketError type BucketExists GenericBucketError
// BucketNotFound - requested bucket not found
type BucketNotFound GenericBucketError type BucketNotFound GenericBucketError
/// Object related errors
// ObjectNotFound - requested object not found
type ObjectNotFound GenericObjectError
// ObjectExists - object already exists
type ObjectExists GenericObjectError
// ObjectNameInvalid - object name provided is invalid
type ObjectNameInvalid GenericObjectError type ObjectNameInvalid GenericObjectError
// Return string an error formatted as the given text // Return string an error formatted as the given text
func (self ImplementationError) Error() string { func (e ImplementationError) Error() string {
error := "" error := ""
if self.Bucket != "" { if e.Bucket != "" {
error = error + "Bucket: " + self.Bucket + " " error = error + "Bucket: " + e.Bucket + " "
} }
if self.Object != "" { if e.Object != "" {
error = error + "Object: " + self.Object + " " error = error + "Object: " + e.Object + " "
} }
error = error + "Error: " + self.Err.Error() error = error + "Error: " + e.Err.Error()
return error return error
} }
// Wrapper function for error object // EmbedError - wrapper function for error object
func EmbedError(bucket, object string, err error) ImplementationError { func EmbedError(bucket, object string, err error) ImplementationError {
return ImplementationError{ return ImplementationError{
Bucket: bucket, Bucket: bucket,
@ -81,46 +95,46 @@ func EmbedError(bucket, object string, err error) ImplementationError {
} }
// Return string an error formatted as the given text // Return string an error formatted as the given text
func (self BucketPolicyNotFound) Error() string { func (e BucketPolicyNotFound) Error() string {
return "Bucket policy not found for: " + self.Bucket return "Bucket policy not found for: " + e.Bucket
} }
// Return string an error formatted as the given text // Return string an error formatted as the given text
func (self ObjectNotFound) Error() string { func (e ObjectNotFound) Error() string {
return "Object not Found: " + self.Bucket + "#" + self.Object return "Object not Found: " + e.Bucket + "#" + e.Object
} }
// Return string an error formatted as the given text // Return string an error formatted as the given text
func (self ApiNotImplemented) Error() string { func (e APINotImplemented) Error() string {
return "Api not implemented: " + self.Api return "Api not implemented: " + e.API
} }
// Return string an error formatted as the given text // Return string an error formatted as the given text
func (self ObjectExists) Error() string { func (e ObjectExists) Error() string {
return "Object exists: " + self.Bucket + "#" + self.Key return "Object exists: " + e.Bucket + "#" + e.Object
} }
// Return string an error formatted as the given text // Return string an error formatted as the given text
func (self BucketNameInvalid) Error() string { func (e BucketNameInvalid) Error() string {
return "Bucket name invalid: " + self.Bucket return "Bucket name invalid: " + e.Bucket
} }
// Return string an error formatted as the given text // Return string an error formatted as the given text
func (self BucketExists) Error() string { func (e BucketExists) Error() string {
return "Bucket exists: " + self.Bucket return "Bucket exists: " + e.Bucket
} }
// Return string an error formatted as the given text // Return string an error formatted as the given text
func (self BucketNotFound) Error() string { func (e BucketNotFound) Error() string {
return "Bucket not Found: " + self.Bucket return "Bucket not Found: " + e.Bucket
} }
// Return string an error formatted as the given text // Return string an error formatted as the given text
func (self ObjectNameInvalid) Error() string { func (e ObjectNameInvalid) Error() string {
return "Object name invalid: " + self.Bucket + "#" + self.Object return "Object name invalid: " + e.Bucket + "#" + e.Object
} }
// Return string an error formatted as the given text // Return string an error formatted as the given text
func (self BackendCorrupted) Error() string { func (e BackendCorrupted) Error() string {
return "Backend corrupted: " + self.Path return "Backend corrupted: " + e.Path
} }

View File

@ -5,6 +5,7 @@
// Package crc32 implements the 32-bit cyclic redundancy check, or CRC-32, // Package crc32 implements the 32-bit cyclic redundancy check, or CRC-32,
// checksum. See http://en.wikipedia.org/wiki/Cyclic_redundancy_check for // checksum. See http://en.wikipedia.org/wiki/Cyclic_redundancy_check for
// information. // information.
package crc32c package crc32c
import ( import (
@ -38,7 +39,7 @@ func (d *digest) Sum(in []byte) []byte {
return append(in, byte(s>>24), byte(s>>16), byte(s>>8), byte(s)) return append(in, byte(s>>24), byte(s>>16), byte(s>>8), byte(s))
} }
// Return current crc in digest object // Sum32 - return current crc in digest object
func (d *digest) Sum32() uint32 { return d.crc } func (d *digest) Sum32() uint32 { return d.crc }
// Reset default crc // Reset default crc
@ -57,7 +58,7 @@ func (d *digest) Write(p []byte) (n int, err error) {
/// Convenience functions /// Convenience functions
// Single caller crc helper // Sum32 - single caller crc helper
func Sum32(data []byte) uint32 { func Sum32(data []byte) uint32 {
crc32 := New() crc32 := New()
crc32.Reset() crc32.Reset()
@ -65,7 +66,7 @@ func Sum32(data []byte) uint32 {
return crc32.Sum32() return crc32.Sum32()
} }
// Low memory footprint io.Reader based crc helper // Sum - low memory footprint io.Reader based crc helper
func Sum(reader io.Reader) (uint32, error) { func Sum(reader io.Reader) (uint32, error) {
h := New() h := New()
var err error var err error

View File

@ -25,6 +25,7 @@ import (
"sync" "sync"
) )
// Config context
type Config struct { type Config struct {
configPath string configPath string
configFile string configFile string
@ -32,13 +33,14 @@ type Config struct {
Users map[string]User Users map[string]User
} }
// User context
type User struct { type User struct {
Name string Name string
AccessKey string AccessKey string
SecretKey string SecretKey string
} }
// Initialize config directory and template config // SetupConfig initialize config directory and template config
func (c *Config) SetupConfig() error { func (c *Config) SetupConfig() error {
u, err := user.Current() u, err := user.Current()
if err != nil { if err != nil {
@ -63,12 +65,12 @@ func (c *Config) SetupConfig() error {
return nil return nil
} }
// Get config file location // GetConfigPath config file location
func (c *Config) GetConfigPath() string { func (c *Config) GetConfigPath() string {
return c.configPath return c.configPath
} }
// Verify if user exists // IsUserExists verify if user exists
func (c *Config) IsUserExists(username string) bool { func (c *Config) IsUserExists(username string) bool {
for _, user := range c.Users { for _, user := range c.Users {
if user.Name == username { if user.Name == username {
@ -78,16 +80,7 @@ func (c *Config) IsUserExists(username string) bool {
return false return false
} }
// Get user based on accesskey // GetUser - get user from username
func (c *Config) GetKey(accessKey string) User {
value, ok := c.Users[accessKey]
if !ok {
return User{}
}
return value
}
// Get user based on username
func (c *Config) GetUser(username string) User { func (c *Config) GetUser(username string) User {
for _, user := range c.Users { for _, user := range c.Users {
if user.Name == username { if user.Name == username {
@ -97,7 +90,7 @@ func (c *Config) GetUser(username string) User {
return User{} return User{}
} }
// Add a new user into existing User list // AddUser - add a user into existing User list
func (c *Config) AddUser(user User) { func (c *Config) AddUser(user User) {
var currentUsers map[string]User var currentUsers map[string]User
if len(c.Users) == 0 { if len(c.Users) == 0 {
@ -109,7 +102,7 @@ func (c *Config) AddUser(user User) {
c.Users = currentUsers c.Users = currentUsers
} }
// Write encoded json in config file // WriteConfig - write encoded json in config file
func (c *Config) WriteConfig() error { func (c *Config) WriteConfig() error {
c.configLock.Lock() c.configLock.Lock()
defer c.configLock.Unlock() defer c.configLock.Unlock()
@ -128,7 +121,7 @@ func (c *Config) WriteConfig() error {
return nil return nil
} }
// Read json config file and decode // ReadConfig - read json config file and decode
func (c *Config) ReadConfig() error { func (c *Config) ReadConfig() error {
c.configLock.RLock() c.configLock.RLock()
defer c.configLock.RUnlock() defer c.configLock.RUnlock()
@ -155,29 +148,3 @@ func (c *Config) ReadConfig() error {
return err return err
} }
} }
/// helpers
// Load all users into memory
func Loadusers() map[string]User {
c := Config{}
c.SetupConfig()
c.ReadConfig()
return c.Users
}
// Load a given user based on accessKey
func Loadkey(accessKeyId string) User {
c := Config{}
c.SetupConfig()
c.ReadConfig()
return c.GetKey(accessKeyId)
}
// Load a given user based on username
func Loaduser(username string) User {
c := Config{}
c.SetupConfig()
c.ReadConfig()
return c.GetUser(username)
}

View File

@ -46,8 +46,8 @@ func (s *MySuite) TestConfig(c *C) {
} }
conf.configLock = new(sync.RWMutex) conf.configLock = new(sync.RWMutex)
accesskey, _ := keys.GetRandomAlphaNumeric(keys.MINIO_ACCESS_ID) accesskey, _ := keys.GenerateRandomAlphaNumeric(keys.MinioAccessID)
secretkey, _ := keys.GetRandomBase64(keys.MINIO_SECRET_ID) secretkey, _ := keys.GenerateRandomBase64(keys.MinioSecretID)
user := User{ user := User{
Name: "gnubot", Name: "gnubot",
@ -62,8 +62,8 @@ func (s *MySuite) TestConfig(c *C) {
err = conf.ReadConfig() err = conf.ReadConfig()
c.Assert(err, IsNil) c.Assert(err, IsNil)
accesskey, _ = keys.GetRandomAlphaNumeric(keys.MINIO_ACCESS_ID) accesskey, _ = keys.GenerateRandomAlphaNumeric(keys.MinioAccessID)
secretkey, _ = keys.GetRandomBase64(keys.MINIO_SECRET_ID) secretkey, _ = keys.GenerateRandomBase64(keys.MinioSecretID)
user = User{ user = User{
Name: "minio", Name: "minio",
AccessKey: string(accesskey), AccessKey: string(accesskey),

View File

@ -32,7 +32,7 @@ type MySuite struct{}
var _ = Suite(&MySuite{}) var _ = Suite(&MySuite{})
func hasCpuFeatureFromOS(feature string) (bool, error) { func hasCPUFeatureFromOS(feature string) (bool, error) {
if runtime.GOOS == "linux" { if runtime.GOOS == "linux" {
command := exec.Command("/bin/cat", "/proc/cpuinfo") command := exec.Command("/bin/cat", "/proc/cpuinfo")
output, err := command.Output() output, err := command.Output()
@ -41,19 +41,16 @@ func hasCpuFeatureFromOS(feature string) (bool, error) {
} }
if strings.Contains(string(output), feature) { if strings.Contains(string(output), feature) {
return true, nil return true, nil
} else {
return false, nil
} }
} else { return false, nil
// TODO find new way to test cpu flags on windows
return false, errors.New("Not Implemented on this platform")
} }
return false, errors.New("Not Implemented on this platform")
} }
func (s *MySuite) TestHasSSE41(c *C) { func (s *MySuite) TestHasSSE41(c *C) {
if runtime.GOOS == "linux" { if runtime.GOOS == "linux" {
var flag = HasSSE41() var flag = HasSSE41()
osCheck, err := hasCpuFeatureFromOS("sse4_1") osCheck, err := hasCPUFeatureFromOS("sse4_1")
c.Assert(err, IsNil) c.Assert(err, IsNil)
c.Check(flag, Equals, osCheck) c.Check(flag, Equals, osCheck)
} }
@ -62,7 +59,7 @@ func (s *MySuite) TestHasSSE41(c *C) {
func (s *MySuite) TestHasAVX(c *C) { func (s *MySuite) TestHasAVX(c *C) {
if runtime.GOOS == "linux" { if runtime.GOOS == "linux" {
var flag = HasAVX() var flag = HasAVX()
osFlag, err := hasCpuFeatureFromOS("avx") osFlag, err := hasCPUFeatureFromOS("avx")
c.Assert(err, IsNil) c.Assert(err, IsNil)
c.Check(osFlag, Equals, flag) c.Check(osFlag, Equals, flag)
} }
@ -71,7 +68,7 @@ func (s *MySuite) TestHasAVX(c *C) {
func (s *MySuite) TestHasAVX2(c *C) { func (s *MySuite) TestHasAVX2(c *C) {
if runtime.GOOS == "linux" { if runtime.GOOS == "linux" {
var flag = HasAVX2() var flag = HasAVX2()
osFlag, err := hasCpuFeatureFromOS("avx2") osFlag, err := hasCPUFeatureFromOS("avx2")
c.Assert(err, IsNil) c.Assert(err, IsNil)
c.Check(osFlag, Equals, flag) c.Check(osFlag, Equals, flag)
} }

View File

@ -16,9 +16,10 @@
package keys package keys
// AccessID and SecretID length in bytes
const ( const (
MINIO_ACCESS_ID = 20 MinioAccessID = 20
MINIO_SECRET_ID = 40 MinioSecretID = 40
) )
/// helpers /// helpers
@ -28,8 +29,8 @@ func isalnum(c byte) bool {
return '0' <= c && c <= '9' || 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' return '0' <= c && c <= '9' || 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z'
} }
// validate access key for only alphanumeric characters // IsValidAccessKey - validate access key for only alphanumeric characters
func ValidateAccessKey(key []byte) bool { func IsValidAccessKey(key []byte) bool {
for _, char := range key { for _, char := range key {
if isalnum(char) { if isalnum(char) {
continue continue

View File

@ -23,13 +23,10 @@ import (
// Static alphaNumeric table used for generating unique keys // Static alphaNumeric table used for generating unique keys
var alphaNumericTable = []byte("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ") var alphaNumericTable = []byte("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ")
var alphaNumericTableFull = []byte("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789")
/// helpers // GenerateRandomAlphaNumeric - generate random alpha numeric value using only uppercase characters
// Generate random alpha numeric value using only uppercase characters
// takes input as size in integer // takes input as size in integer
func GetRandomAlphaNumeric(size int) ([]byte, error) { func GenerateRandomAlphaNumeric(size int) ([]byte, error) {
alpha := make([]byte, size) alpha := make([]byte, size)
_, err := rand.Read(alpha) _, err := rand.Read(alpha)
if err != nil { if err != nil {
@ -42,22 +39,8 @@ func GetRandomAlphaNumeric(size int) ([]byte, error) {
return alpha, nil return alpha, nil
} }
// Generate random alpha numeric value using all alphanumeric characters // GenerateRandomBase64 - generate random base64 numeric value from a random seed.
// takes input as size in integer func GenerateRandomBase64(size int) ([]byte, error) {
func GetRandomAlphaNumericFull(size int) ([]byte, error) {
alphaFull := make([]byte, size)
_, err := rand.Read(alphaFull)
if err != nil {
return nil, err
}
for i := 0; i < size; i++ {
alphaFull[i] = alphaNumericTableFull[alphaFull[i]%byte(len(alphaNumericTableFull))]
}
return alphaFull, nil
}
// Generate random base64 numeric value from a random seed.
func GetRandomBase64(size int) ([]byte, error) {
rb := make([]byte, size) rb := make([]byte, size)
_, err := rand.Read(rb) _, err := rand.Read(rb)
if err != nil { if err != nil {

View File

@ -29,10 +29,10 @@ type MySuite struct{}
var _ = Suite(&MySuite{}) var _ = Suite(&MySuite{})
func (s *MySuite) Testing(c *C) { func (s *MySuite) Testing(c *C) {
value, err := GetRandomBase64(MINIO_SECRET_ID) value, err := GenerateRandomBase64(MinioSecretID)
c.Assert(err, IsNil) c.Assert(err, IsNil)
alphanum, err := GetRandomAlphaNumeric(MINIO_ACCESS_ID) alphanum, err := GenerateRandomAlphaNumeric(MinioAccessID)
c.Assert(err, IsNil) c.Assert(err, IsNil)
c.Log(string(value)) c.Log(string(value))

View File

@ -21,7 +21,7 @@ import (
"io" "io"
) )
// Low memory footprint io.Reader based md5sum helper // Sum - low memory footprint io.Reader based md5sum helper
func Sum(reader io.Reader) ([]byte, error) { func Sum(reader io.Reader) ([]byte, error) {
hash := md5.New() hash := md5.New()
var err error var err error

View File

@ -143,7 +143,7 @@ func (d *digest) checkSum() [Size]byte {
/// Convenience functions /// Convenience functions
// Single caller sha1 helper // Sum1 - single caller sha1 helper
func Sum1(data []byte) [Size]byte { func Sum1(data []byte) [Size]byte {
var d digest var d digest
d.Reset() d.Reset()
@ -151,7 +151,7 @@ func Sum1(data []byte) [Size]byte {
return d.checkSum() return d.checkSum()
} }
// io.Reader based streaming sha1 helper // Sum - io.Reader based streaming sha1 helper
func Sum(reader io.Reader) ([]byte, error) { func Sum(reader io.Reader) ([]byte, error) {
h := New() h := New()
var err error var err error

View File

@ -151,7 +151,7 @@ func (d *digest) checkSum() [Size]byte {
/// Convenience functions /// Convenience functions
// Single caller sha256 helper // Sum256 - single caller sha256 helper
func Sum256(data []byte) [Size]byte { func Sum256(data []byte) [Size]byte {
var d digest var d digest
d.Reset() d.Reset()
@ -159,7 +159,7 @@ func Sum256(data []byte) [Size]byte {
return d.checkSum() return d.checkSum()
} }
// io.Reader based streaming sha256 helper // Sum - io.Reader based streaming sha256 helper
func Sum(reader io.Reader) ([]byte, error) { func Sum(reader io.Reader) ([]byte, error) {
h := New() h := New()
var err error var err error

View File

@ -157,7 +157,7 @@ func (d *digest) checkSum() [Size]byte {
/// Convenience functions /// Convenience functions
// Single caller sha512 helper // Sum512 - single caller sha512 helper
func Sum512(data []byte) [Size]byte { func Sum512(data []byte) [Size]byte {
var d digest var d digest
d.Reset() d.Reset()
@ -165,7 +165,7 @@ func Sum512(data []byte) [Size]byte {
return d.checkSum() return d.checkSum()
} }
// io.Reader based streaming sha512 helper // Sum - io.Reader based streaming sha512 helper
func Sum(reader io.Reader) ([]byte, error) { func Sum(reader io.Reader) ([]byte, error) {
h := New() h := New()
var err error var err error
@ -182,7 +182,7 @@ func Sum(reader io.Reader) ([]byte, error) {
return h.Sum(nil), nil return h.Sum(nil), nil
} }
// Similar to 'Sum()' but returns a [Size]byte // SumStream - similar to 'Sum()' but returns a [Size]byte
func SumStream(reader io.Reader) ([Size]byte, error) { func SumStream(reader io.Reader) ([Size]byte, error) {
var returnValue [Size]byte var returnValue [Size]byte
sumSlice, err := Sum(reader) sumSlice, err := Sum(reader)

View File

@ -32,7 +32,7 @@ import (
"github.com/minio-io/minio/pkg/utils/config" "github.com/minio-io/minio/pkg/utils/config"
) )
// Sign a given http request using HMAC style signatures // SignRequest - a given http request using HMAC style signatures
func SignRequest(user config.User, req *http.Request) { func SignRequest(user config.User, req *http.Request) {
if date := req.Header.Get("Date"); date == "" { if date := req.Header.Get("Date"); date == "" {
req.Header.Set("Date", time.Now().UTC().Format(http.TimeFormat)) req.Header.Set("Date", time.Now().UTC().Format(http.TimeFormat))
@ -49,7 +49,7 @@ func SignRequest(user config.User, req *http.Request) {
req.Header.Set("Authorization", authHeader.String()) req.Header.Set("Authorization", authHeader.String())
} }
// Validate an API request by validating its signature using HMAC signatures // ValidateRequest - an API request by validating its signature using HMAC signatures
func ValidateRequest(user config.User, req *http.Request) (bool, error) { func ValidateRequest(user config.User, req *http.Request) (bool, error) {
// Verify if date headers are set, if not reject the request // Verify if date headers are set, if not reject the request
if req.Header.Get("x-amz-date") == "" { if req.Header.Get("x-amz-date") == "" {
@ -117,7 +117,7 @@ func hasPrefixCaseInsensitive(s, pfx string) bool {
// Canonicalize amazon special headers, headers starting with 'x-amz-' // Canonicalize amazon special headers, headers starting with 'x-amz-'
func writeCanonicalizedAmzHeaders(buf *bytes.Buffer, req *http.Request) { func writeCanonicalizedAmzHeaders(buf *bytes.Buffer, req *http.Request) {
amzHeaders := make([]string, 0) var amzHeaders []string
vals := make(map[string][]string) vals := make(map[string][]string)
for k, vv := range req.Header { for k, vv := range req.Header {
if hasPrefixCaseInsensitive(k, "x-amz-") { if hasPrefixCaseInsensitive(k, "x-amz-") {

View File

@ -31,13 +31,14 @@ import (
"time" "time"
) )
// Based on http://golang.org/src/crypto/tls/generate_cert.go // Certificates - based on http://golang.org/src/crypto/tls/generate_cert.go
type Certificates struct { type Certificates struct {
CertPemBlock []byte CertPemBlock []byte
CertKeyBlock []byte CertKeyBlock []byte
} }
type X509Params struct { // Params - various x.509 parameters
type Params struct {
Hostname string Hostname string
IsCA bool IsCA bool
EcdsaCurve string EcdsaCurve string
@ -72,9 +73,9 @@ func pemBlockForKey(priv interface{}) *pem.Block {
} }
} }
// Generate certificates using custom parameters // GenerateCertificates - generate certificates using custom x.509 parameters
func (tls *Certificates) GenerateCertificates(params X509Params) error { func (tls *Certificates) GenerateCertificates(params Params) error {
var rsaBits int = 2048 var rsaBits = 2048
var priv interface{} var priv interface{}
var err error var err error

View File

@ -31,7 +31,7 @@ var _ = Suite(&MySuite{})
func (s *MySuite) Testing(c *C) { func (s *MySuite) Testing(c *C) {
certObj := Certificates{} certObj := Certificates{}
params := X509Params{ params := Params{
Hostname: "example.com", Hostname: "example.com",
IsCA: false, IsCA: false,
EcdsaCurve: "P224", EcdsaCurve: "P224",

View File

@ -6,19 +6,19 @@ import (
"strings" "strings"
) )
// For 0000-00-00 Date type // Date - [0000-00-00]
type Date struct { type Date struct {
Year int16 Year int16
Month byte Month byte
Day byte Day byte
} }
// Date to string output in yyyy-mm-dd format // String output in yyyy-mm-dd format
func (d Date) String() string { func (d Date) String() string {
return fmt.Sprintf("%04d-%02d-%02d", d.Year, d.Month, d.Day) return fmt.Sprintf("%04d-%02d-%02d", d.Year, d.Month, d.Day)
} }
// True if date is 0000-00-00 // IsZero true if date is 0000-00-00
func (d Date) IsZero() bool { func (d Date) IsZero() bool {
return d.Day == 0 && d.Month == 0 && d.Year == 0 return d.Day == 0 && d.Month == 0 && d.Year == 0
} }

View File

@ -6,35 +6,41 @@ import (
"strings" "strings"
) )
type UserCred struct { // User - AWS canonical
type User struct {
AWS string AWS string
} }
type Stmt struct { // Statement - AWS policy statement
type Statement struct {
Sid string Sid string
Effect string Effect string
Principal UserCred Principal User
Action []string Action []string
Resource []string Resource []string
// TODO fix it in future if necessary - Condition {} // TODO fix it in future if necessary - Condition {}
} }
// BucketPolicy - AWS policy collection
type BucketPolicy struct { type BucketPolicy struct {
Version string // date in 0000-00-00 format Version string // date in 0000-00-00 format
Statement []Stmt Statement []Statement
} }
// Resource delimiter
const ( const (
AwsResource = "arn:aws:s3:::" AwsResource = "arn:aws:s3:::"
MinioResource = "minio:::" MinioResource = "minio:::"
) )
// TODO support canonical user // TODO support canonical user
// Principal delimiter
const ( const (
AwsPrincipal = "arn:aws:iam::" AwsPrincipal = "arn:aws:iam::"
MinioPrincipal = "minio::" MinioPrincipal = "minio::"
) )
// Action map
var SupportedActionMap = map[string]bool{ var SupportedActionMap = map[string]bool{
"*": true, "*": true,
"s3:GetObject": true, "s3:GetObject": true,
@ -47,22 +53,19 @@ var SupportedActionMap = map[string]bool{
"s3:PutBucketPolicy": true, "s3:PutBucketPolicy": true,
} }
// Effect map
var SupportedEffectMap = map[string]bool{ var SupportedEffectMap = map[string]bool{
"Allow": true, "Allow": true,
"Deny": true, "Deny": true,
} }
func isValidAction(action []string) bool { func isValidAction(action []string) bool {
var ok bool = false
for _, a := range action { for _, a := range action {
if !SupportedActionMap[a] { if !SupportedActionMap[a] {
goto error return false
} }
} }
ok = true return true
error:
return ok
} }
func isValidEffect(effect string) bool { func isValidEffect(effect string) bool {
@ -73,7 +76,7 @@ func isValidEffect(effect string) bool {
} }
func isValidResource(resources []string) bool { func isValidResource(resources []string) bool {
var ok bool = false var ok bool
for _, resource := range resources { for _, resource := range resources {
switch true { switch true {
case strings.HasPrefix(resource, AwsResource): case strings.HasPrefix(resource, AwsResource):
@ -96,7 +99,7 @@ func isValidResource(resources []string) bool {
} }
func isValidPrincipal(principal string) bool { func isValidPrincipal(principal string) bool {
var ok bool = false var ok bool
if principal == "*" { if principal == "*" {
return true return true
} }
@ -120,7 +123,7 @@ func isValidPrincipal(principal string) bool {
return ok return ok
} }
// validate request body is proper JSON // Parsepolicy - validate request body is proper JSON and in accordance with policy standards
func Parsepolicy(data io.Reader) (BucketPolicy, bool) { func Parsepolicy(data io.Reader) (BucketPolicy, bool) {
var policy BucketPolicy var policy BucketPolicy
decoder := json.NewDecoder(data) decoder := json.NewDecoder(data)

View File

@ -27,13 +27,13 @@ import (
"strings" "strings"
) )
// Message structure for results from the SplitStream goroutine // Message - message structure for results from the Stream goroutine
type SplitMessage struct { type Message struct {
Data []byte Data []byte
Err error Err error
} }
// SplitStream reads from io.Reader, splits the data into chunks, and sends // Stream reads from io.Reader, splits the data into chunks, and sends
// each chunk to the channel. This method runs until an EOF or error occurs. If // each chunk to the channel. This method runs until an EOF or error occurs. If
// an error occurs, the method sends the error over the channel and returns. // an error occurs, the method sends the error over the channel and returns.
// Before returning, the channel is always closed. // Before returning, the channel is always closed.
@ -41,18 +41,18 @@ type SplitMessage struct {
// The user should run this as a gorountine and retrieve the data over the // The user should run this as a gorountine and retrieve the data over the
// channel. // channel.
// //
// channel := make(chan SplitMessage) // channel := make(chan Message)
// go SplitStream(reader, chunkSize, channel) // go Stream(reader, chunkSize, channel)
// for chunk := range channel { // for chunk := range channel {
// log.Println(chunk.Data) // log.Println(chunk.Data)
// } // }
func SplitStream(reader io.Reader, chunkSize uint64) <-chan SplitMessage { func Stream(reader io.Reader, chunkSize uint64) <-chan Message {
ch := make(chan SplitMessage) ch := make(chan Message)
go splitStreamGoRoutine(reader, chunkSize, ch) go splitStreamGoRoutine(reader, chunkSize, ch)
return ch return ch
} }
func splitStreamGoRoutine(reader io.Reader, chunkSize uint64, ch chan SplitMessage) { func splitStreamGoRoutine(reader io.Reader, chunkSize uint64, ch chan Message) {
// we read until EOF or another error // we read until EOF or another error
var readError error var readError error
@ -81,12 +81,12 @@ func splitStreamGoRoutine(reader io.Reader, chunkSize uint64, ch chan SplitMessa
bytesWriter.Flush() bytesWriter.Flush()
// if we have data available, send it over the channel // if we have data available, send it over the channel
if bytesBuffer.Len() != 0 { if bytesBuffer.Len() != 0 {
ch <- SplitMessage{bytesBuffer.Bytes(), nil} ch <- Message{bytesBuffer.Bytes(), nil}
} }
} }
// if we have an error other than an EOF, send it over the channel // if we have an error other than an EOF, send it over the channel
if readError != io.EOF { if readError != io.EOF {
ch <- SplitMessage{nil, readError} ch <- Message{nil, readError}
} }
// close the channel, signaling the channel reader that the stream is complete // close the channel, signaling the channel reader that the stream is complete
close(ch) close(ch)
@ -142,9 +142,9 @@ func joinFilesGoRoutine(fileInfos []os.FileInfo, writer *io.PipeWriter) {
writer.Close() writer.Close()
} }
// Takes a file and splits it into chunks with size chunkSize. The output // FileWithPrefix - Takes a file and splits it into chunks with size chunkSize. The output
// filename is given with outputPrefix. // filename is given with outputPrefix.
func SplitFileWithPrefix(filename string, chunkSize uint64, outputPrefix string) error { func FileWithPrefix(filename string, chunkSize uint64, outputPrefix string) error {
// open file // open file
file, err := os.Open(filename) file, err := os.Open(filename)
defer file.Close() defer file.Close()
@ -157,7 +157,7 @@ func SplitFileWithPrefix(filename string, chunkSize uint64, outputPrefix string)
} }
// start stream splitting goroutine // start stream splitting goroutine
ch := SplitStream(file, chunkSize) ch := Stream(file, chunkSize)
// used to write each chunk out as a separate file. {{outputPrefix}}.{{i}} // used to write each chunk out as a separate file. {{outputPrefix}}.{{i}}
i := 0 i := 0

View File

@ -41,7 +41,7 @@ func (s *MySuite) TestSplitStream(c *C) {
} }
bytesWriter.Flush() bytesWriter.Flush()
reader := bytes.NewReader(bytesBuffer.Bytes()) reader := bytes.NewReader(bytesBuffer.Bytes())
ch := SplitStream(reader, 25) ch := Stream(reader, 25)
var resultsBuffer bytes.Buffer var resultsBuffer bytes.Buffer
resultsWriter := bufio.NewWriter(&resultsBuffer) resultsWriter := bufio.NewWriter(&resultsBuffer)
for chunk := range ch { for chunk := range ch {
@ -52,9 +52,9 @@ func (s *MySuite) TestSplitStream(c *C) {
} }
func (s *MySuite) TestFileSplitJoin(c *C) { func (s *MySuite) TestFileSplitJoin(c *C) {
err := SplitFileWithPrefix("test-data/TESTFILE", 1024, "TESTPREFIX") err := FileWithPrefix("test-data/TESTFILE", 1024, "TESTPREFIX")
c.Assert(err, IsNil) c.Assert(err, IsNil)
err = SplitFileWithPrefix("test-data/TESTFILE", 1024, "") err = FileWithPrefix("test-data/TESTFILE", 1024, "")
c.Assert(err, Not(IsNil)) c.Assert(err, Not(IsNil))
devnull, err := os.OpenFile(os.DevNull, 2, os.ModeAppend) devnull, err := os.OpenFile(os.DevNull, 2, os.ModeAppend)