|
|
|
/*
|
|
|
|
* Minio Cloud Storage, (C) 2015, 2016 Minio, Inc.
|
|
|
|
*
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
*
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
|
|
|
*/
|
|
|
|
|
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"encoding/base64"
|
|
|
|
"encoding/hex"
|
|
|
|
"encoding/xml"
|
|
|
|
"io"
|
|
|
|
"io/ioutil"
|
|
|
|
"mime/multipart"
|
|
|
|
"net/http"
|
accessPolicy: Implement Put, Get, Delete access policy.
This patch implements Get,Put,Delete bucket policies
Supporting - http://docs.aws.amazon.com/AmazonS3/latest/dev/access-policy-language-overview.html
Currently supports following actions.
"*": true,
"s3:*": true,
"s3:GetObject": true,
"s3:ListBucket": true,
"s3:PutObject": true,
"s3:CreateBucket": true,
"s3:GetBucketLocation": true,
"s3:DeleteBucket": true,
"s3:DeleteObject": true,
"s3:AbortMultipartUpload": true,
"s3:ListBucketMultipartUploads": true,
"s3:ListMultipartUploadParts": true,
following conditions for "StringEquals" and "StringNotEquals"
"s3:prefix", "s3:max-keys"
9 years ago
|
|
|
"net/url"
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
mux "github.com/gorilla/mux"
|
|
|
|
)
|
|
|
|
|
|
|
|
// http://docs.aws.amazon.com/AmazonS3/latest/dev/using-with-s3-actions.html
|
|
|
|
func enforceBucketPolicy(action string, bucket string, reqURL *url.URL) (s3Error APIErrorCode) {
|
accessPolicy: Implement Put, Get, Delete access policy.
This patch implements Get,Put,Delete bucket policies
Supporting - http://docs.aws.amazon.com/AmazonS3/latest/dev/access-policy-language-overview.html
Currently supports following actions.
"*": true,
"s3:*": true,
"s3:GetObject": true,
"s3:ListBucket": true,
"s3:PutObject": true,
"s3:CreateBucket": true,
"s3:GetBucketLocation": true,
"s3:DeleteBucket": true,
"s3:DeleteObject": true,
"s3:AbortMultipartUpload": true,
"s3:ListBucketMultipartUploads": true,
"s3:ListMultipartUploadParts": true,
following conditions for "StringEquals" and "StringNotEquals"
"s3:prefix", "s3:max-keys"
9 years ago
|
|
|
// Read saved bucket policy.
|
|
|
|
policy, err := readBucketPolicy(bucket)
|
|
|
|
if err != nil {
|
|
|
|
errorIf(err, "Unable read bucket policy.")
|
|
|
|
switch err.(type) {
|
fs: Break fs package to top-level and introduce ObjectAPI interface.
ObjectAPI interface brings in changes needed for XL ObjectAPI layer.
The new interface for any ObjectAPI layer is as below
```
// ObjectAPI interface.
type ObjectAPI interface {
// Bucket resource API.
DeleteBucket(bucket string) *probe.Error
ListBuckets() ([]BucketInfo, *probe.Error)
MakeBucket(bucket string) *probe.Error
GetBucketInfo(bucket string) (BucketInfo, *probe.Error)
// Bucket query API.
ListObjects(bucket, prefix, marker, delimiter string, maxKeys int) (ListObjectsResult, *probe.Error)
ListMultipartUploads(bucket string, resources BucketMultipartResourcesMetadata) (BucketMultipartResourcesMetadata, *probe.Error)
// Object resource API.
GetObject(bucket, object string, startOffset int64) (io.ReadCloser, *probe.Error)
GetObjectInfo(bucket, object string) (ObjectInfo, *probe.Error)
PutObject(bucket string, object string, size int64, data io.Reader, metadata map[string]string) (ObjectInfo, *probe.Error)
DeleteObject(bucket, object string) *probe.Error
// Object query API.
NewMultipartUpload(bucket, object string) (string, *probe.Error)
PutObjectPart(bucket, object, uploadID string, partID int, size int64, data io.Reader, md5Hex string) (string, *probe.Error)
ListObjectParts(bucket, object string, resources ObjectResourcesMetadata) (ObjectResourcesMetadata, *probe.Error)
CompleteMultipartUpload(bucket string, object string, uploadID string, parts []CompletePart) (ObjectInfo, *probe.Error)
AbortMultipartUpload(bucket, object, uploadID string) *probe.Error
}
```
9 years ago
|
|
|
case BucketNotFound:
|
|
|
|
return ErrNoSuchBucket
|
fs: Break fs package to top-level and introduce ObjectAPI interface.
ObjectAPI interface brings in changes needed for XL ObjectAPI layer.
The new interface for any ObjectAPI layer is as below
```
// ObjectAPI interface.
type ObjectAPI interface {
// Bucket resource API.
DeleteBucket(bucket string) *probe.Error
ListBuckets() ([]BucketInfo, *probe.Error)
MakeBucket(bucket string) *probe.Error
GetBucketInfo(bucket string) (BucketInfo, *probe.Error)
// Bucket query API.
ListObjects(bucket, prefix, marker, delimiter string, maxKeys int) (ListObjectsResult, *probe.Error)
ListMultipartUploads(bucket string, resources BucketMultipartResourcesMetadata) (BucketMultipartResourcesMetadata, *probe.Error)
// Object resource API.
GetObject(bucket, object string, startOffset int64) (io.ReadCloser, *probe.Error)
GetObjectInfo(bucket, object string) (ObjectInfo, *probe.Error)
PutObject(bucket string, object string, size int64, data io.Reader, metadata map[string]string) (ObjectInfo, *probe.Error)
DeleteObject(bucket, object string) *probe.Error
// Object query API.
NewMultipartUpload(bucket, object string) (string, *probe.Error)
PutObjectPart(bucket, object, uploadID string, partID int, size int64, data io.Reader, md5Hex string) (string, *probe.Error)
ListObjectParts(bucket, object string, resources ObjectResourcesMetadata) (ObjectResourcesMetadata, *probe.Error)
CompleteMultipartUpload(bucket string, object string, uploadID string, parts []CompletePart) (ObjectInfo, *probe.Error)
AbortMultipartUpload(bucket, object, uploadID string) *probe.Error
}
```
9 years ago
|
|
|
case BucketNameInvalid:
|
|
|
|
return ErrInvalidBucketName
|
accessPolicy: Implement Put, Get, Delete access policy.
This patch implements Get,Put,Delete bucket policies
Supporting - http://docs.aws.amazon.com/AmazonS3/latest/dev/access-policy-language-overview.html
Currently supports following actions.
"*": true,
"s3:*": true,
"s3:GetObject": true,
"s3:ListBucket": true,
"s3:PutObject": true,
"s3:CreateBucket": true,
"s3:GetBucketLocation": true,
"s3:DeleteBucket": true,
"s3:DeleteObject": true,
"s3:AbortMultipartUpload": true,
"s3:ListBucketMultipartUploads": true,
"s3:ListMultipartUploadParts": true,
following conditions for "StringEquals" and "StringNotEquals"
"s3:prefix", "s3:max-keys"
9 years ago
|
|
|
default:
|
|
|
|
// For any other error just return AccessDenied.
|
|
|
|
return ErrAccessDenied
|
accessPolicy: Implement Put, Get, Delete access policy.
This patch implements Get,Put,Delete bucket policies
Supporting - http://docs.aws.amazon.com/AmazonS3/latest/dev/access-policy-language-overview.html
Currently supports following actions.
"*": true,
"s3:*": true,
"s3:GetObject": true,
"s3:ListBucket": true,
"s3:PutObject": true,
"s3:CreateBucket": true,
"s3:GetBucketLocation": true,
"s3:DeleteBucket": true,
"s3:DeleteObject": true,
"s3:AbortMultipartUpload": true,
"s3:ListBucketMultipartUploads": true,
"s3:ListMultipartUploadParts": true,
following conditions for "StringEquals" and "StringNotEquals"
"s3:prefix", "s3:max-keys"
9 years ago
|
|
|
}
|
|
|
|
}
|
|
|
|
// Parse the saved policy.
|
|
|
|
bucketPolicy, err := parseBucketPolicy(policy)
|
|
|
|
if err != nil {
|
|
|
|
errorIf(err, "Unable to parse bucket policy.")
|
|
|
|
return ErrAccessDenied
|
accessPolicy: Implement Put, Get, Delete access policy.
This patch implements Get,Put,Delete bucket policies
Supporting - http://docs.aws.amazon.com/AmazonS3/latest/dev/access-policy-language-overview.html
Currently supports following actions.
"*": true,
"s3:*": true,
"s3:GetObject": true,
"s3:ListBucket": true,
"s3:PutObject": true,
"s3:CreateBucket": true,
"s3:GetBucketLocation": true,
"s3:DeleteBucket": true,
"s3:DeleteObject": true,
"s3:AbortMultipartUpload": true,
"s3:ListBucketMultipartUploads": true,
"s3:ListMultipartUploadParts": true,
following conditions for "StringEquals" and "StringNotEquals"
"s3:prefix", "s3:max-keys"
9 years ago
|
|
|
}
|
|
|
|
|
|
|
|
// Construct resource in 'arn:aws:s3:::examplebucket/object' format.
|
bucketpolicy: Improve bucket policy validation, avoid nested rules.
Bucket policy validation is more stricter now, to avoid nested
rules. The reason to do this is keep the rules simpler and more
meaningful avoiding conflicts.
This patch implements stricter checks.
Example policy to be generally avoided.
```
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"s3:GetObject",
"s3:DeleteObject"
],
"Effect": "Allow",
"Principal": {
"AWS": [
"*"
]
},
"Resource": [
"arn:aws:s3:::jarjarbing/*"
]
},
{
"Action": [
"s3:GetObject",
"s3:DeleteObject"
],
"Effect": "Deny",
"Principal": {
"AWS": [
"*"
]
},
"Resource": [
"arn:aws:s3:::jarjarbing/restic/key/*"
]
}
]
}
```
9 years ago
|
|
|
resource := AWSResourcePrefix + strings.TrimPrefix(reqURL.Path, "/")
|
accessPolicy: Implement Put, Get, Delete access policy.
This patch implements Get,Put,Delete bucket policies
Supporting - http://docs.aws.amazon.com/AmazonS3/latest/dev/access-policy-language-overview.html
Currently supports following actions.
"*": true,
"s3:*": true,
"s3:GetObject": true,
"s3:ListBucket": true,
"s3:PutObject": true,
"s3:CreateBucket": true,
"s3:GetBucketLocation": true,
"s3:DeleteBucket": true,
"s3:DeleteObject": true,
"s3:AbortMultipartUpload": true,
"s3:ListBucketMultipartUploads": true,
"s3:ListMultipartUploadParts": true,
following conditions for "StringEquals" and "StringNotEquals"
"s3:prefix", "s3:max-keys"
9 years ago
|
|
|
|
|
|
|
// Get conditions for policy verification.
|
|
|
|
conditions := make(map[string]string)
|
|
|
|
for queryParam := range reqURL.Query() {
|
|
|
|
conditions[queryParam] = reqURL.Query().Get(queryParam)
|
accessPolicy: Implement Put, Get, Delete access policy.
This patch implements Get,Put,Delete bucket policies
Supporting - http://docs.aws.amazon.com/AmazonS3/latest/dev/access-policy-language-overview.html
Currently supports following actions.
"*": true,
"s3:*": true,
"s3:GetObject": true,
"s3:ListBucket": true,
"s3:PutObject": true,
"s3:CreateBucket": true,
"s3:GetBucketLocation": true,
"s3:DeleteBucket": true,
"s3:DeleteObject": true,
"s3:AbortMultipartUpload": true,
"s3:ListBucketMultipartUploads": true,
"s3:ListMultipartUploadParts": true,
following conditions for "StringEquals" and "StringNotEquals"
"s3:prefix", "s3:max-keys"
9 years ago
|
|
|
}
|
|
|
|
|
|
|
|
// Validate action, resource and conditions with current policy statements.
|
bucketpolicy: Improve bucket policy validation, avoid nested rules.
Bucket policy validation is more stricter now, to avoid nested
rules. The reason to do this is keep the rules simpler and more
meaningful avoiding conflicts.
This patch implements stricter checks.
Example policy to be generally avoided.
```
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"s3:GetObject",
"s3:DeleteObject"
],
"Effect": "Allow",
"Principal": {
"AWS": [
"*"
]
},
"Resource": [
"arn:aws:s3:::jarjarbing/*"
]
},
{
"Action": [
"s3:GetObject",
"s3:DeleteObject"
],
"Effect": "Deny",
"Principal": {
"AWS": [
"*"
]
},
"Resource": [
"arn:aws:s3:::jarjarbing/restic/key/*"
]
}
]
}
```
9 years ago
|
|
|
if !bucketPolicyEvalStatements(action, resource, conditions, bucketPolicy.Statements) {
|
|
|
|
return ErrAccessDenied
|
accessPolicy: Implement Put, Get, Delete access policy.
This patch implements Get,Put,Delete bucket policies
Supporting - http://docs.aws.amazon.com/AmazonS3/latest/dev/access-policy-language-overview.html
Currently supports following actions.
"*": true,
"s3:*": true,
"s3:GetObject": true,
"s3:ListBucket": true,
"s3:PutObject": true,
"s3:CreateBucket": true,
"s3:GetBucketLocation": true,
"s3:DeleteBucket": true,
"s3:DeleteObject": true,
"s3:AbortMultipartUpload": true,
"s3:ListBucketMultipartUploads": true,
"s3:ListMultipartUploadParts": true,
following conditions for "StringEquals" and "StringNotEquals"
"s3:prefix", "s3:max-keys"
9 years ago
|
|
|
}
|
|
|
|
return ErrNone
|
accessPolicy: Implement Put, Get, Delete access policy.
This patch implements Get,Put,Delete bucket policies
Supporting - http://docs.aws.amazon.com/AmazonS3/latest/dev/access-policy-language-overview.html
Currently supports following actions.
"*": true,
"s3:*": true,
"s3:GetObject": true,
"s3:ListBucket": true,
"s3:PutObject": true,
"s3:CreateBucket": true,
"s3:GetBucketLocation": true,
"s3:DeleteBucket": true,
"s3:DeleteObject": true,
"s3:AbortMultipartUpload": true,
"s3:ListBucketMultipartUploads": true,
"s3:ListMultipartUploadParts": true,
following conditions for "StringEquals" and "StringNotEquals"
"s3:prefix", "s3:max-keys"
9 years ago
|
|
|
}
|
|
|
|
|
|
|
|
// GetBucketLocationHandler - GET Bucket location.
|
|
|
|
// -------------------------
|
|
|
|
// This operation returns bucket location.
|
|
|
|
func (api objectAPIHandlers) GetBucketLocationHandler(w http.ResponseWriter, r *http.Request) {
|
|
|
|
vars := mux.Vars(r)
|
|
|
|
bucket := vars["bucket"]
|
|
|
|
|
accessPolicy: Implement Put, Get, Delete access policy.
This patch implements Get,Put,Delete bucket policies
Supporting - http://docs.aws.amazon.com/AmazonS3/latest/dev/access-policy-language-overview.html
Currently supports following actions.
"*": true,
"s3:*": true,
"s3:GetObject": true,
"s3:ListBucket": true,
"s3:PutObject": true,
"s3:CreateBucket": true,
"s3:GetBucketLocation": true,
"s3:DeleteBucket": true,
"s3:DeleteObject": true,
"s3:AbortMultipartUpload": true,
"s3:ListBucketMultipartUploads": true,
"s3:ListMultipartUploadParts": true,
following conditions for "StringEquals" and "StringNotEquals"
"s3:prefix", "s3:max-keys"
9 years ago
|
|
|
switch getRequestAuthType(r) {
|
|
|
|
default:
|
|
|
|
// For all unknown auth types return error.
|
|
|
|
writeErrorResponse(w, r, ErrAccessDenied, r.URL.Path)
|
|
|
|
return
|
accessPolicy: Implement Put, Get, Delete access policy.
This patch implements Get,Put,Delete bucket policies
Supporting - http://docs.aws.amazon.com/AmazonS3/latest/dev/access-policy-language-overview.html
Currently supports following actions.
"*": true,
"s3:*": true,
"s3:GetObject": true,
"s3:ListBucket": true,
"s3:PutObject": true,
"s3:CreateBucket": true,
"s3:GetBucketLocation": true,
"s3:DeleteBucket": true,
"s3:DeleteObject": true,
"s3:AbortMultipartUpload": true,
"s3:ListBucketMultipartUploads": true,
"s3:ListMultipartUploadParts": true,
following conditions for "StringEquals" and "StringNotEquals"
"s3:prefix", "s3:max-keys"
9 years ago
|
|
|
case authTypeAnonymous:
|
|
|
|
// http://docs.aws.amazon.com/AmazonS3/latest/dev/using-with-s3-actions.html
|
|
|
|
if s3Error := enforceBucketPolicy("s3:GetBucketLocation", bucket, r.URL); s3Error != ErrNone {
|
accessPolicy: Implement Put, Get, Delete access policy.
This patch implements Get,Put,Delete bucket policies
Supporting - http://docs.aws.amazon.com/AmazonS3/latest/dev/access-policy-language-overview.html
Currently supports following actions.
"*": true,
"s3:*": true,
"s3:GetObject": true,
"s3:ListBucket": true,
"s3:PutObject": true,
"s3:CreateBucket": true,
"s3:GetBucketLocation": true,
"s3:DeleteBucket": true,
"s3:DeleteObject": true,
"s3:AbortMultipartUpload": true,
"s3:ListBucketMultipartUploads": true,
"s3:ListMultipartUploadParts": true,
following conditions for "StringEquals" and "StringNotEquals"
"s3:prefix", "s3:max-keys"
9 years ago
|
|
|
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
case authTypeSigned, authTypePresigned:
|
|
|
|
payload, err := ioutil.ReadAll(r.Body)
|
|
|
|
if err != nil {
|
|
|
|
writeErrorResponse(w, r, ErrInternalError, r.URL.Path)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
// Verify Content-Md5, if payload is set.
|
|
|
|
if r.Header.Get("Content-Md5") != "" {
|
|
|
|
if r.Header.Get("Content-Md5") != base64.StdEncoding.EncodeToString(sumMD5(payload)) {
|
|
|
|
writeErrorResponse(w, r, ErrBadDigest, r.URL.Path)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Populate back the payload.
|
|
|
|
r.Body = ioutil.NopCloser(bytes.NewReader(payload))
|
|
|
|
var s3Error APIErrorCode // API error code.
|
|
|
|
validateRegion := false // Validate region.
|
|
|
|
if isRequestSignatureV4(r) {
|
|
|
|
s3Error = doesSignatureMatch(hex.EncodeToString(sum256(payload)), r, validateRegion)
|
|
|
|
} else if isRequestPresignedSignatureV4(r) {
|
|
|
|
s3Error = doesPresignedSignatureMatch(hex.EncodeToString(sum256(payload)), r, validateRegion)
|
|
|
|
}
|
|
|
|
if s3Error != ErrNone {
|
accessPolicy: Implement Put, Get, Delete access policy.
This patch implements Get,Put,Delete bucket policies
Supporting - http://docs.aws.amazon.com/AmazonS3/latest/dev/access-policy-language-overview.html
Currently supports following actions.
"*": true,
"s3:*": true,
"s3:GetObject": true,
"s3:ListBucket": true,
"s3:PutObject": true,
"s3:CreateBucket": true,
"s3:GetBucketLocation": true,
"s3:DeleteBucket": true,
"s3:DeleteObject": true,
"s3:AbortMultipartUpload": true,
"s3:ListBucketMultipartUploads": true,
"s3:ListMultipartUploadParts": true,
following conditions for "StringEquals" and "StringNotEquals"
"s3:prefix", "s3:max-keys"
9 years ago
|
|
|
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if _, err := api.ObjectAPI.GetBucketInfo(bucket); err != nil {
|
|
|
|
errorIf(err, "Unable to fetch bucket info.")
|
|
|
|
writeErrorResponse(w, r, toAPIErrorCode(err), r.URL.Path)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Generate response.
|
|
|
|
encodedSuccessResponse := encodeResponse(LocationResponse{})
|
config/main: Re-write config files - add to new config v3
- New config format.
```
{
"version": "3",
"address": ":9000",
"backend": {
"type": "fs",
"disk": "/path"
},
"credential": {
"accessKey": "WLGDGYAQYIGI833EV05A",
"secretKey": "BYvgJM101sHngl2uzjXS/OBF/aMxAN06JrJ3qJlF"
},
"region": "us-east-1",
"logger": {
"file": {
"enable": false,
"fileName": "",
"level": "error"
},
"syslog": {
"enable": false,
"address": "",
"level": "debug"
},
"console": {
"enable": true,
"level": "fatal"
}
}
}
```
New command lines in lieu of supporting XL.
Minio initialize filesystem backend.
~~~
$ minio init fs <path>
~~~
Minio initialize XL backend.
~~~
$ minio init xl <url1>...<url16>
~~~
For 'fs' backend it starts the server.
~~~
$ minio server
~~~
For 'xl' backend it waits for servers to join.
~~~
$ minio server
... [PROGRESS BAR] of servers connecting
~~~
Now on other servers execute 'join' and they connect.
~~~
....
minio join <url1> -- from <url2> && minio server
minio join <url1> -- from <url3> && minio server
...
...
minio join <url1> -- from <url16> && minio server
~~~
9 years ago
|
|
|
// Get current region.
|
|
|
|
region := serverConfig.GetRegion()
|
|
|
|
if region != "us-east-1" {
|
|
|
|
encodedSuccessResponse = encodeResponse(LocationResponse{
|
config/main: Re-write config files - add to new config v3
- New config format.
```
{
"version": "3",
"address": ":9000",
"backend": {
"type": "fs",
"disk": "/path"
},
"credential": {
"accessKey": "WLGDGYAQYIGI833EV05A",
"secretKey": "BYvgJM101sHngl2uzjXS/OBF/aMxAN06JrJ3qJlF"
},
"region": "us-east-1",
"logger": {
"file": {
"enable": false,
"fileName": "",
"level": "error"
},
"syslog": {
"enable": false,
"address": "",
"level": "debug"
},
"console": {
"enable": true,
"level": "fatal"
}
}
}
```
New command lines in lieu of supporting XL.
Minio initialize filesystem backend.
~~~
$ minio init fs <path>
~~~
Minio initialize XL backend.
~~~
$ minio init xl <url1>...<url16>
~~~
For 'fs' backend it starts the server.
~~~
$ minio server
~~~
For 'xl' backend it waits for servers to join.
~~~
$ minio server
... [PROGRESS BAR] of servers connecting
~~~
Now on other servers execute 'join' and they connect.
~~~
....
minio join <url1> -- from <url2> && minio server
minio join <url1> -- from <url3> && minio server
...
...
minio join <url1> -- from <url16> && minio server
~~~
9 years ago
|
|
|
Location: region,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
setCommonHeaders(w) // Write headers.
|
|
|
|
writeSuccessResponse(w, encodedSuccessResponse)
|
|
|
|
}
|
|
|
|
|
|
|
|
// ListMultipartUploadsHandler - GET Bucket (List Multipart uploads)
|
|
|
|
// -------------------------
|
|
|
|
// This operation lists in-progress multipart uploads. An in-progress
|
|
|
|
// multipart upload is a multipart upload that has been initiated,
|
|
|
|
// using the Initiate Multipart Upload request, but has not yet been
|
|
|
|
// completed or aborted. This operation returns at most 1,000 multipart
|
|
|
|
// uploads in the response.
|
|
|
|
//
|
|
|
|
func (api objectAPIHandlers) ListMultipartUploadsHandler(w http.ResponseWriter, r *http.Request) {
|
|
|
|
vars := mux.Vars(r)
|
|
|
|
bucket := vars["bucket"]
|
|
|
|
|
accessPolicy: Implement Put, Get, Delete access policy.
This patch implements Get,Put,Delete bucket policies
Supporting - http://docs.aws.amazon.com/AmazonS3/latest/dev/access-policy-language-overview.html
Currently supports following actions.
"*": true,
"s3:*": true,
"s3:GetObject": true,
"s3:ListBucket": true,
"s3:PutObject": true,
"s3:CreateBucket": true,
"s3:GetBucketLocation": true,
"s3:DeleteBucket": true,
"s3:DeleteObject": true,
"s3:AbortMultipartUpload": true,
"s3:ListBucketMultipartUploads": true,
"s3:ListMultipartUploadParts": true,
following conditions for "StringEquals" and "StringNotEquals"
"s3:prefix", "s3:max-keys"
9 years ago
|
|
|
switch getRequestAuthType(r) {
|
|
|
|
default:
|
|
|
|
// For all unknown auth types return error.
|
|
|
|
writeErrorResponse(w, r, ErrAccessDenied, r.URL.Path)
|
|
|
|
return
|
accessPolicy: Implement Put, Get, Delete access policy.
This patch implements Get,Put,Delete bucket policies
Supporting - http://docs.aws.amazon.com/AmazonS3/latest/dev/access-policy-language-overview.html
Currently supports following actions.
"*": true,
"s3:*": true,
"s3:GetObject": true,
"s3:ListBucket": true,
"s3:PutObject": true,
"s3:CreateBucket": true,
"s3:GetBucketLocation": true,
"s3:DeleteBucket": true,
"s3:DeleteObject": true,
"s3:AbortMultipartUpload": true,
"s3:ListBucketMultipartUploads": true,
"s3:ListMultipartUploadParts": true,
following conditions for "StringEquals" and "StringNotEquals"
"s3:prefix", "s3:max-keys"
9 years ago
|
|
|
case authTypeAnonymous:
|
|
|
|
// http://docs.aws.amazon.com/AmazonS3/latest/dev/mpuAndPermissions.html
|
|
|
|
if s3Error := enforceBucketPolicy("s3:ListBucketMultipartUploads", bucket, r.URL); s3Error != ErrNone {
|
accessPolicy: Implement Put, Get, Delete access policy.
This patch implements Get,Put,Delete bucket policies
Supporting - http://docs.aws.amazon.com/AmazonS3/latest/dev/access-policy-language-overview.html
Currently supports following actions.
"*": true,
"s3:*": true,
"s3:GetObject": true,
"s3:ListBucket": true,
"s3:PutObject": true,
"s3:CreateBucket": true,
"s3:GetBucketLocation": true,
"s3:DeleteBucket": true,
"s3:DeleteObject": true,
"s3:AbortMultipartUpload": true,
"s3:ListBucketMultipartUploads": true,
"s3:ListMultipartUploadParts": true,
following conditions for "StringEquals" and "StringNotEquals"
"s3:prefix", "s3:max-keys"
9 years ago
|
|
|
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
case authTypePresigned, authTypeSigned:
|
|
|
|
if s3Error := isReqAuthenticated(r); s3Error != ErrNone {
|
accessPolicy: Implement Put, Get, Delete access policy.
This patch implements Get,Put,Delete bucket policies
Supporting - http://docs.aws.amazon.com/AmazonS3/latest/dev/access-policy-language-overview.html
Currently supports following actions.
"*": true,
"s3:*": true,
"s3:GetObject": true,
"s3:ListBucket": true,
"s3:PutObject": true,
"s3:CreateBucket": true,
"s3:GetBucketLocation": true,
"s3:DeleteBucket": true,
"s3:DeleteObject": true,
"s3:AbortMultipartUpload": true,
"s3:ListBucketMultipartUploads": true,
"s3:ListMultipartUploadParts": true,
following conditions for "StringEquals" and "StringNotEquals"
"s3:prefix", "s3:max-keys"
9 years ago
|
|
|
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
objectAPI: Fix object API interface, remove unnecessary structs.
ObjectAPI changes.
```
ListObjects(bucket, prefix, marker, delimiter string, maxKeys int) (ListObjectsInfo, *probe.Error)
ListMultipartUploads(bucket, objectPrefix, keyMarker, uploadIDMarker, delimiter string, maxUploads int) (ListMultipartsInfo, *probe.Error)
ListObjectParts(bucket, object, uploadID string, partNumberMarker, maxParts int) (ListPartsInfo, *probe.Error)
CompleteMultipartUpload(bucket string, object string, uploadID string, parts []completePart) (ObjectInfo, *probe.Error)
```
9 years ago
|
|
|
prefix, keyMarker, uploadIDMarker, delimiter, maxUploads, _ := getBucketMultipartResources(r.URL.Query())
|
|
|
|
if maxUploads < 0 {
|
|
|
|
writeErrorResponse(w, r, ErrInvalidMaxUploads, r.URL.Path)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if keyMarker != "" {
|
|
|
|
// Marker not common with prefix is not implemented.
|
|
|
|
if !strings.HasPrefix(keyMarker, prefix) {
|
|
|
|
writeErrorResponse(w, r, ErrNotImplemented, r.URL.Path)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
objectAPI: Fix object API interface, remove unnecessary structs.
ObjectAPI changes.
```
ListObjects(bucket, prefix, marker, delimiter string, maxKeys int) (ListObjectsInfo, *probe.Error)
ListMultipartUploads(bucket, objectPrefix, keyMarker, uploadIDMarker, delimiter string, maxUploads int) (ListMultipartsInfo, *probe.Error)
ListObjectParts(bucket, object, uploadID string, partNumberMarker, maxParts int) (ListPartsInfo, *probe.Error)
CompleteMultipartUpload(bucket string, object string, uploadID string, parts []completePart) (ObjectInfo, *probe.Error)
```
9 years ago
|
|
|
listMultipartsInfo, err := api.ObjectAPI.ListMultipartUploads(bucket, prefix, keyMarker, uploadIDMarker, delimiter, maxUploads)
|
|
|
|
if err != nil {
|
|
|
|
errorIf(err, "Unable to list multipart uploads.")
|
|
|
|
writeErrorResponse(w, r, toAPIErrorCode(err), r.URL.Path)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
// generate response
|
objectAPI: Fix object API interface, remove unnecessary structs.
ObjectAPI changes.
```
ListObjects(bucket, prefix, marker, delimiter string, maxKeys int) (ListObjectsInfo, *probe.Error)
ListMultipartUploads(bucket, objectPrefix, keyMarker, uploadIDMarker, delimiter string, maxUploads int) (ListMultipartsInfo, *probe.Error)
ListObjectParts(bucket, object, uploadID string, partNumberMarker, maxParts int) (ListPartsInfo, *probe.Error)
CompleteMultipartUpload(bucket string, object string, uploadID string, parts []completePart) (ObjectInfo, *probe.Error)
```
9 years ago
|
|
|
response := generateListMultipartUploadsResponse(bucket, listMultipartsInfo)
|
|
|
|
encodedSuccessResponse := encodeResponse(response)
|
|
|
|
// write headers.
|
|
|
|
setCommonHeaders(w)
|
|
|
|
// write success response.
|
|
|
|
writeSuccessResponse(w, encodedSuccessResponse)
|
|
|
|
}
|
|
|
|
|
|
|
|
// ListObjectsHandler - GET Bucket (List Objects)
|
|
|
|
// -- -----------------------
|
|
|
|
// This implementation of the GET operation returns some or all (up to 1000)
|
|
|
|
// 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.
|
|
|
|
//
|
|
|
|
func (api objectAPIHandlers) ListObjectsHandler(w http.ResponseWriter, r *http.Request) {
|
|
|
|
vars := mux.Vars(r)
|
|
|
|
bucket := vars["bucket"]
|
|
|
|
|
accessPolicy: Implement Put, Get, Delete access policy.
This patch implements Get,Put,Delete bucket policies
Supporting - http://docs.aws.amazon.com/AmazonS3/latest/dev/access-policy-language-overview.html
Currently supports following actions.
"*": true,
"s3:*": true,
"s3:GetObject": true,
"s3:ListBucket": true,
"s3:PutObject": true,
"s3:CreateBucket": true,
"s3:GetBucketLocation": true,
"s3:DeleteBucket": true,
"s3:DeleteObject": true,
"s3:AbortMultipartUpload": true,
"s3:ListBucketMultipartUploads": true,
"s3:ListMultipartUploadParts": true,
following conditions for "StringEquals" and "StringNotEquals"
"s3:prefix", "s3:max-keys"
9 years ago
|
|
|
switch getRequestAuthType(r) {
|
|
|
|
default:
|
|
|
|
// For all unknown auth types return error.
|
|
|
|
writeErrorResponse(w, r, ErrAccessDenied, r.URL.Path)
|
accessPolicy: Implement Put, Get, Delete access policy.
This patch implements Get,Put,Delete bucket policies
Supporting - http://docs.aws.amazon.com/AmazonS3/latest/dev/access-policy-language-overview.html
Currently supports following actions.
"*": true,
"s3:*": true,
"s3:GetObject": true,
"s3:ListBucket": true,
"s3:PutObject": true,
"s3:CreateBucket": true,
"s3:GetBucketLocation": true,
"s3:DeleteBucket": true,
"s3:DeleteObject": true,
"s3:AbortMultipartUpload": true,
"s3:ListBucketMultipartUploads": true,
"s3:ListMultipartUploadParts": true,
following conditions for "StringEquals" and "StringNotEquals"
"s3:prefix", "s3:max-keys"
9 years ago
|
|
|
return
|
|
|
|
case authTypeAnonymous:
|
|
|
|
// http://docs.aws.amazon.com/AmazonS3/latest/dev/using-with-s3-actions.html
|
|
|
|
if s3Error := enforceBucketPolicy("s3:ListBucket", bucket, r.URL); s3Error != ErrNone {
|
accessPolicy: Implement Put, Get, Delete access policy.
This patch implements Get,Put,Delete bucket policies
Supporting - http://docs.aws.amazon.com/AmazonS3/latest/dev/access-policy-language-overview.html
Currently supports following actions.
"*": true,
"s3:*": true,
"s3:GetObject": true,
"s3:ListBucket": true,
"s3:PutObject": true,
"s3:CreateBucket": true,
"s3:GetBucketLocation": true,
"s3:DeleteBucket": true,
"s3:DeleteObject": true,
"s3:AbortMultipartUpload": true,
"s3:ListBucketMultipartUploads": true,
"s3:ListMultipartUploadParts": true,
following conditions for "StringEquals" and "StringNotEquals"
"s3:prefix", "s3:max-keys"
9 years ago
|
|
|
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
case authTypeSigned, authTypePresigned:
|
|
|
|
if s3Error := isReqAuthenticated(r); s3Error != ErrNone {
|
accessPolicy: Implement Put, Get, Delete access policy.
This patch implements Get,Put,Delete bucket policies
Supporting - http://docs.aws.amazon.com/AmazonS3/latest/dev/access-policy-language-overview.html
Currently supports following actions.
"*": true,
"s3:*": true,
"s3:GetObject": true,
"s3:ListBucket": true,
"s3:PutObject": true,
"s3:CreateBucket": true,
"s3:GetBucketLocation": true,
"s3:DeleteBucket": true,
"s3:DeleteObject": true,
"s3:AbortMultipartUpload": true,
"s3:ListBucketMultipartUploads": true,
"s3:ListMultipartUploadParts": true,
following conditions for "StringEquals" and "StringNotEquals"
"s3:prefix", "s3:max-keys"
9 years ago
|
|
|
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO handle encoding type.
|
|
|
|
prefix, marker, delimiter, maxkeys, _ := getBucketResources(r.URL.Query())
|
|
|
|
if maxkeys < 0 {
|
|
|
|
writeErrorResponse(w, r, ErrInvalidMaxKeys, r.URL.Path)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
// Verify if delimiter is anything other than '/', which we do not support.
|
|
|
|
if delimiter != "" && delimiter != "/" {
|
|
|
|
writeErrorResponse(w, r, ErrNotImplemented, r.URL.Path)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
// If marker is set unescape.
|
|
|
|
if marker != "" {
|
|
|
|
// Marker not common with prefix is not implemented.
|
|
|
|
if !strings.HasPrefix(marker, prefix) {
|
|
|
|
writeErrorResponse(w, r, ErrNotImplemented, r.URL.Path)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
objectAPI: Fix object API interface, remove unnecessary structs.
ObjectAPI changes.
```
ListObjects(bucket, prefix, marker, delimiter string, maxKeys int) (ListObjectsInfo, *probe.Error)
ListMultipartUploads(bucket, objectPrefix, keyMarker, uploadIDMarker, delimiter string, maxUploads int) (ListMultipartsInfo, *probe.Error)
ListObjectParts(bucket, object, uploadID string, partNumberMarker, maxParts int) (ListPartsInfo, *probe.Error)
CompleteMultipartUpload(bucket string, object string, uploadID string, parts []completePart) (ObjectInfo, *probe.Error)
```
9 years ago
|
|
|
listObjectsInfo, err := api.ObjectAPI.ListObjects(bucket, prefix, marker, delimiter, maxkeys)
|
|
|
|
if err == nil {
|
|
|
|
// generate response
|
objectAPI: Fix object API interface, remove unnecessary structs.
ObjectAPI changes.
```
ListObjects(bucket, prefix, marker, delimiter string, maxKeys int) (ListObjectsInfo, *probe.Error)
ListMultipartUploads(bucket, objectPrefix, keyMarker, uploadIDMarker, delimiter string, maxUploads int) (ListMultipartsInfo, *probe.Error)
ListObjectParts(bucket, object, uploadID string, partNumberMarker, maxParts int) (ListPartsInfo, *probe.Error)
CompleteMultipartUpload(bucket string, object string, uploadID string, parts []completePart) (ObjectInfo, *probe.Error)
```
9 years ago
|
|
|
response := generateListObjectsResponse(bucket, prefix, marker, delimiter, maxkeys, listObjectsInfo)
|
|
|
|
encodedSuccessResponse := encodeResponse(response)
|
|
|
|
// Write headers
|
|
|
|
setCommonHeaders(w)
|
|
|
|
// Write success response.
|
|
|
|
writeSuccessResponse(w, encodedSuccessResponse)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
errorIf(err, "Unable to list objects.")
|
|
|
|
writeErrorResponse(w, r, toAPIErrorCode(err), r.URL.Path)
|
|
|
|
}
|
|
|
|
|
|
|
|
// ListBucketsHandler - GET Service
|
|
|
|
// -----------
|
|
|
|
// This implementation of the GET operation returns a list of all buckets
|
|
|
|
// owned by the authenticated sender of the request.
|
|
|
|
func (api objectAPIHandlers) ListBucketsHandler(w http.ResponseWriter, r *http.Request) {
|
accessPolicy: Implement Put, Get, Delete access policy.
This patch implements Get,Put,Delete bucket policies
Supporting - http://docs.aws.amazon.com/AmazonS3/latest/dev/access-policy-language-overview.html
Currently supports following actions.
"*": true,
"s3:*": true,
"s3:GetObject": true,
"s3:ListBucket": true,
"s3:PutObject": true,
"s3:CreateBucket": true,
"s3:GetBucketLocation": true,
"s3:DeleteBucket": true,
"s3:DeleteObject": true,
"s3:AbortMultipartUpload": true,
"s3:ListBucketMultipartUploads": true,
"s3:ListMultipartUploadParts": true,
following conditions for "StringEquals" and "StringNotEquals"
"s3:prefix", "s3:max-keys"
9 years ago
|
|
|
// List buckets does not support bucket policies.
|
|
|
|
switch getRequestAuthType(r) {
|
|
|
|
default:
|
|
|
|
// For all unknown auth types return error.
|
|
|
|
writeErrorResponse(w, r, ErrAccessDenied, r.URL.Path)
|
|
|
|
return
|
accessPolicy: Implement Put, Get, Delete access policy.
This patch implements Get,Put,Delete bucket policies
Supporting - http://docs.aws.amazon.com/AmazonS3/latest/dev/access-policy-language-overview.html
Currently supports following actions.
"*": true,
"s3:*": true,
"s3:GetObject": true,
"s3:ListBucket": true,
"s3:PutObject": true,
"s3:CreateBucket": true,
"s3:GetBucketLocation": true,
"s3:DeleteBucket": true,
"s3:DeleteObject": true,
"s3:AbortMultipartUpload": true,
"s3:ListBucketMultipartUploads": true,
"s3:ListMultipartUploadParts": true,
following conditions for "StringEquals" and "StringNotEquals"
"s3:prefix", "s3:max-keys"
9 years ago
|
|
|
case authTypeSigned, authTypePresigned:
|
|
|
|
payload, e := ioutil.ReadAll(r.Body)
|
|
|
|
if e != nil {
|
|
|
|
writeErrorResponse(w, r, ErrInternalError, r.URL.Path)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
// Verify Content-Md5, if payload is set.
|
|
|
|
if r.Header.Get("Content-Md5") != "" {
|
|
|
|
if r.Header.Get("Content-Md5") != base64.StdEncoding.EncodeToString(sumMD5(payload)) {
|
|
|
|
writeErrorResponse(w, r, ErrBadDigest, r.URL.Path)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Populate back the payload.
|
|
|
|
r.Body = ioutil.NopCloser(bytes.NewReader(payload))
|
|
|
|
var s3Error APIErrorCode // API error code.
|
|
|
|
validateRegion := false // Validate region.
|
|
|
|
if isRequestSignatureV4(r) {
|
|
|
|
s3Error = doesSignatureMatch(hex.EncodeToString(sum256(payload)), r, validateRegion)
|
|
|
|
} else if isRequestPresignedSignatureV4(r) {
|
|
|
|
s3Error = doesPresignedSignatureMatch(hex.EncodeToString(sum256(payload)), r, validateRegion)
|
|
|
|
}
|
|
|
|
if s3Error != ErrNone {
|
accessPolicy: Implement Put, Get, Delete access policy.
This patch implements Get,Put,Delete bucket policies
Supporting - http://docs.aws.amazon.com/AmazonS3/latest/dev/access-policy-language-overview.html
Currently supports following actions.
"*": true,
"s3:*": true,
"s3:GetObject": true,
"s3:ListBucket": true,
"s3:PutObject": true,
"s3:CreateBucket": true,
"s3:GetBucketLocation": true,
"s3:DeleteBucket": true,
"s3:DeleteObject": true,
"s3:AbortMultipartUpload": true,
"s3:ListBucketMultipartUploads": true,
"s3:ListMultipartUploadParts": true,
following conditions for "StringEquals" and "StringNotEquals"
"s3:prefix", "s3:max-keys"
9 years ago
|
|
|
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
objectAPI: Fix object API interface, remove unnecessary structs.
ObjectAPI changes.
```
ListObjects(bucket, prefix, marker, delimiter string, maxKeys int) (ListObjectsInfo, *probe.Error)
ListMultipartUploads(bucket, objectPrefix, keyMarker, uploadIDMarker, delimiter string, maxUploads int) (ListMultipartsInfo, *probe.Error)
ListObjectParts(bucket, object, uploadID string, partNumberMarker, maxParts int) (ListPartsInfo, *probe.Error)
CompleteMultipartUpload(bucket string, object string, uploadID string, parts []completePart) (ObjectInfo, *probe.Error)
```
9 years ago
|
|
|
bucketsInfo, err := api.ObjectAPI.ListBuckets()
|
|
|
|
if err == nil {
|
|
|
|
// generate response
|
objectAPI: Fix object API interface, remove unnecessary structs.
ObjectAPI changes.
```
ListObjects(bucket, prefix, marker, delimiter string, maxKeys int) (ListObjectsInfo, *probe.Error)
ListMultipartUploads(bucket, objectPrefix, keyMarker, uploadIDMarker, delimiter string, maxUploads int) (ListMultipartsInfo, *probe.Error)
ListObjectParts(bucket, object, uploadID string, partNumberMarker, maxParts int) (ListPartsInfo, *probe.Error)
CompleteMultipartUpload(bucket string, object string, uploadID string, parts []completePart) (ObjectInfo, *probe.Error)
```
9 years ago
|
|
|
response := generateListBucketsResponse(bucketsInfo)
|
|
|
|
encodedSuccessResponse := encodeResponse(response)
|
|
|
|
// write headers
|
|
|
|
setCommonHeaders(w)
|
|
|
|
// write response
|
|
|
|
writeSuccessResponse(w, encodedSuccessResponse)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
errorIf(err, "Unable to list buckets.")
|
|
|
|
writeErrorResponse(w, r, toAPIErrorCode(err), r.URL.Path)
|
|
|
|
}
|
|
|
|
|
|
|
|
// DeleteMultipleObjectsHandler - deletes multiple objects.
|
|
|
|
func (api objectAPIHandlers) DeleteMultipleObjectsHandler(w http.ResponseWriter, r *http.Request) {
|
|
|
|
vars := mux.Vars(r)
|
|
|
|
bucket := vars["bucket"]
|
|
|
|
|
|
|
|
switch getRequestAuthType(r) {
|
|
|
|
default:
|
|
|
|
// For all unknown auth types return error.
|
|
|
|
writeErrorResponse(w, r, ErrAccessDenied, r.URL.Path)
|
|
|
|
return
|
|
|
|
case authTypeAnonymous:
|
|
|
|
// http://docs.aws.amazon.com/AmazonS3/latest/dev/using-with-s3-actions.html
|
|
|
|
if s3Error := enforceBucketPolicy("s3:DeleteObject", bucket, r.URL); s3Error != ErrNone {
|
|
|
|
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
case authTypePresigned, authTypeSigned:
|
|
|
|
if s3Error := isReqAuthenticated(r); s3Error != ErrNone {
|
|
|
|
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Content-Length is required and should be non-zero
|
|
|
|
// http://docs.aws.amazon.com/AmazonS3/latest/API/multiobjectdeleteapi.html
|
|
|
|
if r.ContentLength <= 0 {
|
|
|
|
writeErrorResponse(w, r, ErrMissingContentLength, r.URL.Path)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Content-Md5 is requied should be set
|
|
|
|
// http://docs.aws.amazon.com/AmazonS3/latest/API/multiobjectdeleteapi.html
|
|
|
|
if _, ok := r.Header["Content-Md5"]; !ok {
|
|
|
|
writeErrorResponse(w, r, ErrMissingContentMD5, r.URL.Path)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Allocate incoming content length bytes.
|
|
|
|
deleteXMLBytes := make([]byte, r.ContentLength)
|
|
|
|
|
|
|
|
// Read incoming body XML bytes.
|
|
|
|
if _, err := io.ReadFull(r.Body, deleteXMLBytes); err != nil {
|
|
|
|
errorIf(err, "Unable to read HTTP body.")
|
|
|
|
writeErrorResponse(w, r, ErrInternalError, r.URL.Path)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Unmarshal list of keys to be deleted.
|
|
|
|
deleteObjects := &DeleteObjectsRequest{}
|
|
|
|
if err := xml.Unmarshal(deleteXMLBytes, deleteObjects); err != nil {
|
|
|
|
errorIf(err, "Unable to unmarshal delete objects request XML.")
|
|
|
|
writeErrorResponse(w, r, ErrMalformedXML, r.URL.Path)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
var deleteErrors []DeleteError
|
|
|
|
var deletedObjects []ObjectIdentifier
|
|
|
|
// Loop through all the objects and delete them sequentially.
|
|
|
|
for _, object := range deleteObjects.Objects {
|
fs: Break fs package to top-level and introduce ObjectAPI interface.
ObjectAPI interface brings in changes needed for XL ObjectAPI layer.
The new interface for any ObjectAPI layer is as below
```
// ObjectAPI interface.
type ObjectAPI interface {
// Bucket resource API.
DeleteBucket(bucket string) *probe.Error
ListBuckets() ([]BucketInfo, *probe.Error)
MakeBucket(bucket string) *probe.Error
GetBucketInfo(bucket string) (BucketInfo, *probe.Error)
// Bucket query API.
ListObjects(bucket, prefix, marker, delimiter string, maxKeys int) (ListObjectsResult, *probe.Error)
ListMultipartUploads(bucket string, resources BucketMultipartResourcesMetadata) (BucketMultipartResourcesMetadata, *probe.Error)
// Object resource API.
GetObject(bucket, object string, startOffset int64) (io.ReadCloser, *probe.Error)
GetObjectInfo(bucket, object string) (ObjectInfo, *probe.Error)
PutObject(bucket string, object string, size int64, data io.Reader, metadata map[string]string) (ObjectInfo, *probe.Error)
DeleteObject(bucket, object string) *probe.Error
// Object query API.
NewMultipartUpload(bucket, object string) (string, *probe.Error)
PutObjectPart(bucket, object, uploadID string, partID int, size int64, data io.Reader, md5Hex string) (string, *probe.Error)
ListObjectParts(bucket, object string, resources ObjectResourcesMetadata) (ObjectResourcesMetadata, *probe.Error)
CompleteMultipartUpload(bucket string, object string, uploadID string, parts []CompletePart) (ObjectInfo, *probe.Error)
AbortMultipartUpload(bucket, object, uploadID string) *probe.Error
}
```
9 years ago
|
|
|
err := api.ObjectAPI.DeleteObject(bucket, object.ObjectName)
|
|
|
|
if err == nil {
|
|
|
|
deletedObjects = append(deletedObjects, ObjectIdentifier{
|
|
|
|
ObjectName: object.ObjectName,
|
|
|
|
})
|
|
|
|
} else {
|
|
|
|
errorIf(err, "Unable to delete object.")
|
|
|
|
deleteErrors = append(deleteErrors, DeleteError{
|
|
|
|
Code: errorCodeResponse[toAPIErrorCode(err)].Code,
|
|
|
|
Message: errorCodeResponse[toAPIErrorCode(err)].Description,
|
|
|
|
Key: object.ObjectName,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Generate response
|
|
|
|
response := generateMultiDeleteResponse(deleteObjects.Quiet, deletedObjects, deleteErrors)
|
|
|
|
encodedSuccessResponse := encodeResponse(response)
|
|
|
|
// Write headers
|
|
|
|
setCommonHeaders(w)
|
|
|
|
// Write success response.
|
|
|
|
writeSuccessResponse(w, encodedSuccessResponse)
|
|
|
|
}
|
|
|
|
|
|
|
|
// PutBucketHandler - PUT Bucket
|
|
|
|
// ----------
|
|
|
|
// This implementation of the PUT operation creates a new bucket for authenticated request
|
|
|
|
func (api objectAPIHandlers) PutBucketHandler(w http.ResponseWriter, r *http.Request) {
|
|
|
|
vars := mux.Vars(r)
|
|
|
|
bucket := vars["bucket"]
|
|
|
|
|
accessPolicy: Implement Put, Get, Delete access policy.
This patch implements Get,Put,Delete bucket policies
Supporting - http://docs.aws.amazon.com/AmazonS3/latest/dev/access-policy-language-overview.html
Currently supports following actions.
"*": true,
"s3:*": true,
"s3:GetObject": true,
"s3:ListBucket": true,
"s3:PutObject": true,
"s3:CreateBucket": true,
"s3:GetBucketLocation": true,
"s3:DeleteBucket": true,
"s3:DeleteObject": true,
"s3:AbortMultipartUpload": true,
"s3:ListBucketMultipartUploads": true,
"s3:ListMultipartUploadParts": true,
following conditions for "StringEquals" and "StringNotEquals"
"s3:prefix", "s3:max-keys"
9 years ago
|
|
|
// Set http request for signature.
|
|
|
|
switch getRequestAuthType(r) {
|
|
|
|
default:
|
|
|
|
// For all unknown auth types return error.
|
|
|
|
writeErrorResponse(w, r, ErrAccessDenied, r.URL.Path)
|
|
|
|
return
|
|
|
|
case authTypePresigned, authTypeSigned:
|
|
|
|
if s3Error := isReqAuthenticated(r); s3Error != ErrNone {
|
|
|
|
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// the location value in the request body should match the Region in serverConfig.
|
|
|
|
// other values of location are not accepted.
|
|
|
|
// make bucket fails in such cases.
|
|
|
|
errCode := isValidLocationContraint(r.Body, serverConfig.GetRegion())
|
|
|
|
if errCode != ErrNone {
|
|
|
|
writeErrorResponse(w, r, errCode, r.URL.Path)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
// Make bucket.
|
fs: Break fs package to top-level and introduce ObjectAPI interface.
ObjectAPI interface brings in changes needed for XL ObjectAPI layer.
The new interface for any ObjectAPI layer is as below
```
// ObjectAPI interface.
type ObjectAPI interface {
// Bucket resource API.
DeleteBucket(bucket string) *probe.Error
ListBuckets() ([]BucketInfo, *probe.Error)
MakeBucket(bucket string) *probe.Error
GetBucketInfo(bucket string) (BucketInfo, *probe.Error)
// Bucket query API.
ListObjects(bucket, prefix, marker, delimiter string, maxKeys int) (ListObjectsResult, *probe.Error)
ListMultipartUploads(bucket string, resources BucketMultipartResourcesMetadata) (BucketMultipartResourcesMetadata, *probe.Error)
// Object resource API.
GetObject(bucket, object string, startOffset int64) (io.ReadCloser, *probe.Error)
GetObjectInfo(bucket, object string) (ObjectInfo, *probe.Error)
PutObject(bucket string, object string, size int64, data io.Reader, metadata map[string]string) (ObjectInfo, *probe.Error)
DeleteObject(bucket, object string) *probe.Error
// Object query API.
NewMultipartUpload(bucket, object string) (string, *probe.Error)
PutObjectPart(bucket, object, uploadID string, partID int, size int64, data io.Reader, md5Hex string) (string, *probe.Error)
ListObjectParts(bucket, object string, resources ObjectResourcesMetadata) (ObjectResourcesMetadata, *probe.Error)
CompleteMultipartUpload(bucket string, object string, uploadID string, parts []CompletePart) (ObjectInfo, *probe.Error)
AbortMultipartUpload(bucket, object, uploadID string) *probe.Error
}
```
9 years ago
|
|
|
err := api.ObjectAPI.MakeBucket(bucket)
|
|
|
|
if err != nil {
|
|
|
|
errorIf(err, "Unable to create a bucket.")
|
|
|
|
writeErrorResponse(w, r, toAPIErrorCode(err), r.URL.Path)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
// Make sure to add Location information here only for bucket
|
|
|
|
w.Header().Set("Location", getLocation(r))
|
|
|
|
writeSuccessResponse(w, nil)
|
|
|
|
}
|
|
|
|
|
|
|
|
func extractHTTPFormValues(reader *multipart.Reader) (io.Reader, map[string]string, error) {
|
|
|
|
/// HTML Form values
|
|
|
|
formValues := make(map[string]string)
|
|
|
|
filePart := new(bytes.Buffer)
|
|
|
|
var err error
|
|
|
|
for err == nil {
|
|
|
|
var part *multipart.Part
|
|
|
|
part, err = reader.NextPart()
|
|
|
|
if part != nil {
|
|
|
|
if part.FileName() == "" {
|
|
|
|
var buffer []byte
|
|
|
|
buffer, err = ioutil.ReadAll(part)
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
|
|
|
formValues[http.CanonicalHeaderKey(part.FormName())] = string(buffer)
|
|
|
|
} else {
|
|
|
|
if _, err = io.Copy(filePart, part); err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return filePart, formValues, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// PostPolicyBucketHandler - POST policy
|
|
|
|
// ----------
|
|
|
|
// This implementation of the POST operation handles object creation with a specified
|
|
|
|
// signature policy in multipart/form-data
|
|
|
|
func (api objectAPIHandlers) PostPolicyBucketHandler(w http.ResponseWriter, r *http.Request) {
|
|
|
|
// Here the parameter is the size of the form data that should
|
|
|
|
// be loaded in memory, the remaining being put in temporary files.
|
|
|
|
reader, err := r.MultipartReader()
|
|
|
|
if err != nil {
|
|
|
|
errorIf(err, "Unable to initialize multipart reader.")
|
|
|
|
writeErrorResponse(w, r, ErrMalformedPOSTRequest, r.URL.Path)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
fileBody, formValues, err := extractHTTPFormValues(reader)
|
|
|
|
if err != nil {
|
|
|
|
errorIf(err, "Unable to parse form values.")
|
|
|
|
writeErrorResponse(w, r, ErrMalformedPOSTRequest, r.URL.Path)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
bucket := mux.Vars(r)["bucket"]
|
|
|
|
formValues["Bucket"] = bucket
|
|
|
|
object := formValues["Key"]
|
|
|
|
|
|
|
|
// Verify policy signature.
|
|
|
|
apiErr := doesPolicySignatureMatch(formValues)
|
|
|
|
if apiErr != ErrNone {
|
|
|
|
writeErrorResponse(w, r, apiErr, r.URL.Path)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if apiErr = checkPostPolicy(formValues); apiErr != ErrNone {
|
|
|
|
writeErrorResponse(w, r, apiErr, r.URL.Path)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Save metadata.
|
|
|
|
metadata := make(map[string]string)
|
|
|
|
// Nothing to store right now.
|
|
|
|
|
|
|
|
md5Sum, err := api.ObjectAPI.PutObject(bucket, object, -1, fileBody, metadata)
|
|
|
|
if err != nil {
|
|
|
|
errorIf(err, "Unable to create object.")
|
|
|
|
writeErrorResponse(w, r, toAPIErrorCode(err), r.URL.Path)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if md5Sum != "" {
|
|
|
|
w.Header().Set("ETag", "\""+md5Sum+"\"")
|
|
|
|
}
|
|
|
|
encodedSuccessResponse := encodeResponse(PostResponse{
|
|
|
|
Location: getObjectLocation(bucket, object), // TODO Full URL is preferred
|
|
|
|
Bucket: bucket,
|
|
|
|
Key: object,
|
|
|
|
ETag: md5Sum,
|
|
|
|
})
|
|
|
|
setCommonHeaders(w)
|
|
|
|
writeSuccessResponse(w, encodedSuccessResponse)
|
|
|
|
}
|
|
|
|
|
|
|
|
// HeadBucketHandler - HEAD Bucket
|
|
|
|
// ----------
|
|
|
|
// This operation is useful to determine if a bucket exists.
|
|
|
|
// The operation returns a 200 OK if the bucket exists and you
|
|
|
|
// have permission to access it. Otherwise, the operation might
|
|
|
|
// return responses such as 404 Not Found and 403 Forbidden.
|
|
|
|
func (api objectAPIHandlers) HeadBucketHandler(w http.ResponseWriter, r *http.Request) {
|
|
|
|
vars := mux.Vars(r)
|
|
|
|
bucket := vars["bucket"]
|
|
|
|
|
accessPolicy: Implement Put, Get, Delete access policy.
This patch implements Get,Put,Delete bucket policies
Supporting - http://docs.aws.amazon.com/AmazonS3/latest/dev/access-policy-language-overview.html
Currently supports following actions.
"*": true,
"s3:*": true,
"s3:GetObject": true,
"s3:ListBucket": true,
"s3:PutObject": true,
"s3:CreateBucket": true,
"s3:GetBucketLocation": true,
"s3:DeleteBucket": true,
"s3:DeleteObject": true,
"s3:AbortMultipartUpload": true,
"s3:ListBucketMultipartUploads": true,
"s3:ListMultipartUploadParts": true,
following conditions for "StringEquals" and "StringNotEquals"
"s3:prefix", "s3:max-keys"
9 years ago
|
|
|
switch getRequestAuthType(r) {
|
|
|
|
default:
|
|
|
|
// For all unknown auth types return error.
|
|
|
|
writeErrorResponse(w, r, ErrAccessDenied, r.URL.Path)
|
accessPolicy: Implement Put, Get, Delete access policy.
This patch implements Get,Put,Delete bucket policies
Supporting - http://docs.aws.amazon.com/AmazonS3/latest/dev/access-policy-language-overview.html
Currently supports following actions.
"*": true,
"s3:*": true,
"s3:GetObject": true,
"s3:ListBucket": true,
"s3:PutObject": true,
"s3:CreateBucket": true,
"s3:GetBucketLocation": true,
"s3:DeleteBucket": true,
"s3:DeleteObject": true,
"s3:AbortMultipartUpload": true,
"s3:ListBucketMultipartUploads": true,
"s3:ListMultipartUploadParts": true,
following conditions for "StringEquals" and "StringNotEquals"
"s3:prefix", "s3:max-keys"
9 years ago
|
|
|
return
|
|
|
|
case authTypeAnonymous:
|
|
|
|
// http://docs.aws.amazon.com/AmazonS3/latest/dev/using-with-s3-actions.html
|
|
|
|
if s3Error := enforceBucketPolicy("s3:ListBucket", bucket, r.URL); s3Error != ErrNone {
|
|
|
|
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
|
|
|
return
|
|
|
|
}
|
accessPolicy: Implement Put, Get, Delete access policy.
This patch implements Get,Put,Delete bucket policies
Supporting - http://docs.aws.amazon.com/AmazonS3/latest/dev/access-policy-language-overview.html
Currently supports following actions.
"*": true,
"s3:*": true,
"s3:GetObject": true,
"s3:ListBucket": true,
"s3:PutObject": true,
"s3:CreateBucket": true,
"s3:GetBucketLocation": true,
"s3:DeleteBucket": true,
"s3:DeleteObject": true,
"s3:AbortMultipartUpload": true,
"s3:ListBucketMultipartUploads": true,
"s3:ListMultipartUploadParts": true,
following conditions for "StringEquals" and "StringNotEquals"
"s3:prefix", "s3:max-keys"
9 years ago
|
|
|
case authTypePresigned, authTypeSigned:
|
|
|
|
if s3Error := isReqAuthenticated(r); s3Error != ErrNone {
|
accessPolicy: Implement Put, Get, Delete access policy.
This patch implements Get,Put,Delete bucket policies
Supporting - http://docs.aws.amazon.com/AmazonS3/latest/dev/access-policy-language-overview.html
Currently supports following actions.
"*": true,
"s3:*": true,
"s3:GetObject": true,
"s3:ListBucket": true,
"s3:PutObject": true,
"s3:CreateBucket": true,
"s3:GetBucketLocation": true,
"s3:DeleteBucket": true,
"s3:DeleteObject": true,
"s3:AbortMultipartUpload": true,
"s3:ListBucketMultipartUploads": true,
"s3:ListMultipartUploadParts": true,
following conditions for "StringEquals" and "StringNotEquals"
"s3:prefix", "s3:max-keys"
9 years ago
|
|
|
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if _, err := api.ObjectAPI.GetBucketInfo(bucket); err != nil {
|
|
|
|
errorIf(err, "Unable to fetch bucket info.")
|
|
|
|
writeErrorResponse(w, r, toAPIErrorCode(err), r.URL.Path)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
writeSuccessResponse(w, nil)
|
|
|
|
}
|
|
|
|
|
|
|
|
// DeleteBucketHandler - Delete bucket
|
|
|
|
func (api objectAPIHandlers) DeleteBucketHandler(w http.ResponseWriter, r *http.Request) {
|
|
|
|
vars := mux.Vars(r)
|
|
|
|
bucket := vars["bucket"]
|
|
|
|
|
accessPolicy: Implement Put, Get, Delete access policy.
This patch implements Get,Put,Delete bucket policies
Supporting - http://docs.aws.amazon.com/AmazonS3/latest/dev/access-policy-language-overview.html
Currently supports following actions.
"*": true,
"s3:*": true,
"s3:GetObject": true,
"s3:ListBucket": true,
"s3:PutObject": true,
"s3:CreateBucket": true,
"s3:GetBucketLocation": true,
"s3:DeleteBucket": true,
"s3:DeleteObject": true,
"s3:AbortMultipartUpload": true,
"s3:ListBucketMultipartUploads": true,
"s3:ListMultipartUploadParts": true,
following conditions for "StringEquals" and "StringNotEquals"
"s3:prefix", "s3:max-keys"
9 years ago
|
|
|
switch getRequestAuthType(r) {
|
|
|
|
default:
|
|
|
|
// For all unknown auth types return error.
|
|
|
|
writeErrorResponse(w, r, ErrAccessDenied, r.URL.Path)
|
|
|
|
return
|
accessPolicy: Implement Put, Get, Delete access policy.
This patch implements Get,Put,Delete bucket policies
Supporting - http://docs.aws.amazon.com/AmazonS3/latest/dev/access-policy-language-overview.html
Currently supports following actions.
"*": true,
"s3:*": true,
"s3:GetObject": true,
"s3:ListBucket": true,
"s3:PutObject": true,
"s3:CreateBucket": true,
"s3:GetBucketLocation": true,
"s3:DeleteBucket": true,
"s3:DeleteObject": true,
"s3:AbortMultipartUpload": true,
"s3:ListBucketMultipartUploads": true,
"s3:ListMultipartUploadParts": true,
following conditions for "StringEquals" and "StringNotEquals"
"s3:prefix", "s3:max-keys"
9 years ago
|
|
|
case authTypePresigned, authTypeSigned:
|
|
|
|
if s3Error := isReqAuthenticated(r); s3Error != ErrNone {
|
accessPolicy: Implement Put, Get, Delete access policy.
This patch implements Get,Put,Delete bucket policies
Supporting - http://docs.aws.amazon.com/AmazonS3/latest/dev/access-policy-language-overview.html
Currently supports following actions.
"*": true,
"s3:*": true,
"s3:GetObject": true,
"s3:ListBucket": true,
"s3:PutObject": true,
"s3:CreateBucket": true,
"s3:GetBucketLocation": true,
"s3:DeleteBucket": true,
"s3:DeleteObject": true,
"s3:AbortMultipartUpload": true,
"s3:ListBucketMultipartUploads": true,
"s3:ListMultipartUploadParts": true,
following conditions for "StringEquals" and "StringNotEquals"
"s3:prefix", "s3:max-keys"
9 years ago
|
|
|
writeErrorResponse(w, r, s3Error, r.URL.Path)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := api.ObjectAPI.DeleteBucket(bucket); err != nil {
|
|
|
|
errorIf(err, "Unable to delete a bucket.")
|
|
|
|
writeErrorResponse(w, r, toAPIErrorCode(err), r.URL.Path)
|
|
|
|
return
|
|
|
|
}
|
accessPolicy: Implement Put, Get, Delete access policy.
This patch implements Get,Put,Delete bucket policies
Supporting - http://docs.aws.amazon.com/AmazonS3/latest/dev/access-policy-language-overview.html
Currently supports following actions.
"*": true,
"s3:*": true,
"s3:GetObject": true,
"s3:ListBucket": true,
"s3:PutObject": true,
"s3:CreateBucket": true,
"s3:GetBucketLocation": true,
"s3:DeleteBucket": true,
"s3:DeleteObject": true,
"s3:AbortMultipartUpload": true,
"s3:ListBucketMultipartUploads": true,
"s3:ListMultipartUploadParts": true,
following conditions for "StringEquals" and "StringNotEquals"
"s3:prefix", "s3:max-keys"
9 years ago
|
|
|
|
|
|
|
// Delete bucket access policy, if present - ignore any errors.
|
|
|
|
removeBucketPolicy(bucket)
|
|
|
|
|
|
|
|
// Write success response.
|
|
|
|
writeSuccessNoContent(w)
|
|
|
|
}
|