mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2024-01-19 02:48:24 +00:00
refactoring
This commit is contained in:
parent
2c21eb1971
commit
5b40a2690a
|
@ -3,6 +3,7 @@ package s3api
|
|||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"github.com/chrislusf/seaweedfs/weed/s3api/s3err"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
||||
|
@ -125,7 +126,7 @@ func (iam *IdentityAccessManagement) Auth(f http.HandlerFunc, action Action) htt
|
|||
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
errCode := iam.authRequest(r, action)
|
||||
if errCode == ErrNone {
|
||||
if errCode == s3err.ErrNone {
|
||||
f(w, r)
|
||||
return
|
||||
}
|
||||
|
@ -134,16 +135,16 @@ func (iam *IdentityAccessManagement) Auth(f http.HandlerFunc, action Action) htt
|
|||
}
|
||||
|
||||
// check whether the request has valid access keys
|
||||
func (iam *IdentityAccessManagement) authRequest(r *http.Request, action Action) ErrorCode {
|
||||
func (iam *IdentityAccessManagement) authRequest(r *http.Request, action Action) s3err.ErrorCode {
|
||||
var identity *Identity
|
||||
var s3Err ErrorCode
|
||||
var s3Err s3err.ErrorCode
|
||||
var found bool
|
||||
switch getRequestAuthType(r) {
|
||||
case authTypeStreamingSigned:
|
||||
return ErrNone
|
||||
return s3err.ErrNone
|
||||
case authTypeUnknown:
|
||||
glog.V(3).Infof("unknown auth type")
|
||||
return ErrAccessDenied
|
||||
return s3err.ErrAccessDenied
|
||||
case authTypePresignedV2, authTypeSignedV2:
|
||||
glog.V(3).Infof("v2 auth type")
|
||||
identity, s3Err = iam.isReqAuthenticatedV2(r)
|
||||
|
@ -152,21 +153,21 @@ func (iam *IdentityAccessManagement) authRequest(r *http.Request, action Action)
|
|||
identity, s3Err = iam.reqSignatureV4Verify(r)
|
||||
case authTypePostPolicy:
|
||||
glog.V(3).Infof("post policy auth type")
|
||||
return ErrNotImplemented
|
||||
return s3err.ErrNotImplemented
|
||||
case authTypeJWT:
|
||||
glog.V(3).Infof("jwt auth type")
|
||||
return ErrNotImplemented
|
||||
return s3err.ErrNotImplemented
|
||||
case authTypeAnonymous:
|
||||
identity, found = iam.lookupAnonymous()
|
||||
if !found {
|
||||
return ErrAccessDenied
|
||||
return s3err.ErrAccessDenied
|
||||
}
|
||||
default:
|
||||
return ErrNotImplemented
|
||||
return s3err.ErrNotImplemented
|
||||
}
|
||||
|
||||
glog.V(3).Infof("auth error: %v", s3Err)
|
||||
if s3Err != ErrNone {
|
||||
if s3Err != s3err.ErrNone {
|
||||
return s3Err
|
||||
}
|
||||
|
||||
|
@ -175,10 +176,10 @@ func (iam *IdentityAccessManagement) authRequest(r *http.Request, action Action)
|
|||
bucket, _ := getBucketAndObject(r)
|
||||
|
||||
if !identity.canDo(action, bucket) {
|
||||
return ErrAccessDenied
|
||||
return s3err.ErrAccessDenied
|
||||
}
|
||||
|
||||
return ErrNone
|
||||
return s3err.ErrNone
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ import (
|
|||
"crypto/subtle"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"github.com/chrislusf/seaweedfs/weed/s3api/s3err"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
@ -61,7 +62,7 @@ var resourceList = []string{
|
|||
}
|
||||
|
||||
// Verify if request has valid AWS Signature Version '2'.
|
||||
func (iam *IdentityAccessManagement) isReqAuthenticatedV2(r *http.Request) (*Identity, ErrorCode) {
|
||||
func (iam *IdentityAccessManagement) isReqAuthenticatedV2(r *http.Request) (*Identity, s3err.ErrorCode) {
|
||||
if isRequestSignatureV2(r) {
|
||||
return iam.doesSignV2Match(r)
|
||||
}
|
||||
|
@ -88,36 +89,36 @@ func (iam *IdentityAccessManagement) isReqAuthenticatedV2(r *http.Request) (*Ide
|
|||
// - http://docs.aws.amazon.com/AmazonS3/latest/dev/auth-request-sig-v2.html
|
||||
// returns true if matches, false otherwise. if error is not nil then it is always false
|
||||
|
||||
func validateV2AuthHeader(v2Auth string) (accessKey string, errCode ErrorCode) {
|
||||
func validateV2AuthHeader(v2Auth string) (accessKey string, errCode s3err.ErrorCode) {
|
||||
if v2Auth == "" {
|
||||
return "", ErrAuthHeaderEmpty
|
||||
return "", s3err.ErrAuthHeaderEmpty
|
||||
}
|
||||
// Verify if the header algorithm is supported or not.
|
||||
if !strings.HasPrefix(v2Auth, signV2Algorithm) {
|
||||
return "", ErrSignatureVersionNotSupported
|
||||
return "", s3err.ErrSignatureVersionNotSupported
|
||||
}
|
||||
|
||||
// below is V2 Signed Auth header format, splitting on `space` (after the `AWS` string).
|
||||
// Authorization = "AWS" + " " + AWSAccessKeyId + ":" + Signature
|
||||
authFields := strings.Split(v2Auth, " ")
|
||||
if len(authFields) != 2 {
|
||||
return "", ErrMissingFields
|
||||
return "", s3err.ErrMissingFields
|
||||
}
|
||||
|
||||
// Then will be splitting on ":", this will seprate `AWSAccessKeyId` and `Signature` string.
|
||||
keySignFields := strings.Split(strings.TrimSpace(authFields[1]), ":")
|
||||
if len(keySignFields) != 2 {
|
||||
return "", ErrMissingFields
|
||||
return "", s3err.ErrMissingFields
|
||||
}
|
||||
|
||||
return keySignFields[0], ErrNone
|
||||
return keySignFields[0], s3err.ErrNone
|
||||
}
|
||||
|
||||
func (iam *IdentityAccessManagement) doesSignV2Match(r *http.Request) (*Identity, ErrorCode) {
|
||||
func (iam *IdentityAccessManagement) doesSignV2Match(r *http.Request) (*Identity, s3err.ErrorCode) {
|
||||
v2Auth := r.Header.Get("Authorization")
|
||||
|
||||
accessKey, apiError := validateV2AuthHeader(v2Auth)
|
||||
if apiError != ErrNone {
|
||||
if apiError != s3err.ErrNone {
|
||||
return nil, apiError
|
||||
}
|
||||
|
||||
|
@ -125,7 +126,7 @@ func (iam *IdentityAccessManagement) doesSignV2Match(r *http.Request) (*Identity
|
|||
// Validate if access key id same.
|
||||
ident, cred, found := iam.lookupByAccessKey(accessKey)
|
||||
if !found {
|
||||
return nil, ErrInvalidAccessKeyID
|
||||
return nil, s3err.ErrInvalidAccessKeyID
|
||||
}
|
||||
|
||||
// r.RequestURI will have raw encoded URI as sent by the client.
|
||||
|
@ -138,30 +139,30 @@ func (iam *IdentityAccessManagement) doesSignV2Match(r *http.Request) (*Identity
|
|||
|
||||
unescapedQueries, err := unescapeQueries(encodedQuery)
|
||||
if err != nil {
|
||||
return nil, ErrInvalidQueryParams
|
||||
return nil, s3err.ErrInvalidQueryParams
|
||||
}
|
||||
|
||||
encodedResource, err = getResource(encodedResource, r.Host, iam.domain)
|
||||
if err != nil {
|
||||
return nil, ErrInvalidRequest
|
||||
return nil, s3err.ErrInvalidRequest
|
||||
}
|
||||
|
||||
prefix := fmt.Sprintf("%s %s:", signV2Algorithm, cred.AccessKey)
|
||||
if !strings.HasPrefix(v2Auth, prefix) {
|
||||
return nil, ErrSignatureDoesNotMatch
|
||||
return nil, s3err.ErrSignatureDoesNotMatch
|
||||
}
|
||||
v2Auth = v2Auth[len(prefix):]
|
||||
expectedAuth := signatureV2(cred, r.Method, encodedResource, strings.Join(unescapedQueries, "&"), r.Header)
|
||||
if !compareSignatureV2(v2Auth, expectedAuth) {
|
||||
return nil, ErrSignatureDoesNotMatch
|
||||
return nil, s3err.ErrSignatureDoesNotMatch
|
||||
}
|
||||
return ident, ErrNone
|
||||
return ident, s3err.ErrNone
|
||||
}
|
||||
|
||||
// doesPresignV2SignatureMatch - Verify query headers with presigned signature
|
||||
// - http://docs.aws.amazon.com/AmazonS3/latest/dev/RESTAuthentication.html#RESTAuthenticationQueryStringAuth
|
||||
// returns ErrNone if matches. S3 errors otherwise.
|
||||
func (iam *IdentityAccessManagement) doesPresignV2SignatureMatch(r *http.Request) (*Identity, ErrorCode) {
|
||||
func (iam *IdentityAccessManagement) doesPresignV2SignatureMatch(r *http.Request) (*Identity, s3err.ErrorCode) {
|
||||
|
||||
// r.RequestURI will have raw encoded URI as sent by the client.
|
||||
tokens := strings.SplitN(r.RequestURI, "?", 2)
|
||||
|
@ -182,14 +183,14 @@ func (iam *IdentityAccessManagement) doesPresignV2SignatureMatch(r *http.Request
|
|||
var unescapedQueries []string
|
||||
unescapedQueries, err = unescapeQueries(encodedQuery)
|
||||
if err != nil {
|
||||
return nil, ErrInvalidQueryParams
|
||||
return nil, s3err.ErrInvalidQueryParams
|
||||
}
|
||||
|
||||
// Extract the necessary values from presigned query, construct a list of new filtered queries.
|
||||
for _, query := range unescapedQueries {
|
||||
keyval := strings.SplitN(query, "=", 2)
|
||||
if len(keyval) != 2 {
|
||||
return nil, ErrInvalidQueryParams
|
||||
return nil, s3err.ErrInvalidQueryParams
|
||||
}
|
||||
switch keyval[0] {
|
||||
case "AWSAccessKeyId":
|
||||
|
@ -205,37 +206,37 @@ func (iam *IdentityAccessManagement) doesPresignV2SignatureMatch(r *http.Request
|
|||
|
||||
// Invalid values returns error.
|
||||
if accessKey == "" || gotSignature == "" || expires == "" {
|
||||
return nil, ErrInvalidQueryParams
|
||||
return nil, s3err.ErrInvalidQueryParams
|
||||
}
|
||||
|
||||
// Validate if access key id same.
|
||||
ident, cred, found := iam.lookupByAccessKey(accessKey)
|
||||
if !found {
|
||||
return nil, ErrInvalidAccessKeyID
|
||||
return nil, s3err.ErrInvalidAccessKeyID
|
||||
}
|
||||
|
||||
// Make sure the request has not expired.
|
||||
expiresInt, err := strconv.ParseInt(expires, 10, 64)
|
||||
if err != nil {
|
||||
return nil, ErrMalformedExpires
|
||||
return nil, s3err.ErrMalformedExpires
|
||||
}
|
||||
|
||||
// Check if the presigned URL has expired.
|
||||
if expiresInt < time.Now().UTC().Unix() {
|
||||
return nil, ErrExpiredPresignRequest
|
||||
return nil, s3err.ErrExpiredPresignRequest
|
||||
}
|
||||
|
||||
encodedResource, err = getResource(encodedResource, r.Host, iam.domain)
|
||||
if err != nil {
|
||||
return nil, ErrInvalidRequest
|
||||
return nil, s3err.ErrInvalidRequest
|
||||
}
|
||||
|
||||
expectedSignature := preSignatureV2(cred, r.Method, encodedResource, strings.Join(filteredQueries, "&"), r.Header, expires)
|
||||
if !compareSignatureV2(gotSignature, expectedSignature) {
|
||||
return nil, ErrSignatureDoesNotMatch
|
||||
return nil, s3err.ErrSignatureDoesNotMatch
|
||||
}
|
||||
|
||||
return ident, ErrNone
|
||||
return ident, s3err.ErrNone
|
||||
}
|
||||
|
||||
// Escape encodedQuery string into unescaped list of query params, returns error
|
||||
|
|
|
@ -23,6 +23,7 @@ import (
|
|||
"crypto/sha256"
|
||||
"crypto/subtle"
|
||||
"encoding/hex"
|
||||
"github.com/chrislusf/seaweedfs/weed/s3api/s3err"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"regexp"
|
||||
|
@ -33,7 +34,7 @@ import (
|
|||
"unicode/utf8"
|
||||
)
|
||||
|
||||
func (iam *IdentityAccessManagement) reqSignatureV4Verify(r *http.Request) (*Identity, ErrorCode) {
|
||||
func (iam *IdentityAccessManagement) reqSignatureV4Verify(r *http.Request) (*Identity, s3err.ErrorCode) {
|
||||
sha256sum := getContentSha256Cksum(r)
|
||||
switch {
|
||||
case isRequestSignatureV4(r):
|
||||
|
@ -41,7 +42,7 @@ func (iam *IdentityAccessManagement) reqSignatureV4Verify(r *http.Request) (*Ide
|
|||
case isRequestPresignedSignatureV4(r):
|
||||
return iam.doesPresignedSignatureMatch(sha256sum, r)
|
||||
}
|
||||
return nil, ErrAccessDenied
|
||||
return nil, s3err.ErrAccessDenied
|
||||
}
|
||||
|
||||
// Streaming AWS Signature Version '4' constants.
|
||||
|
@ -89,7 +90,7 @@ func getContentSha256Cksum(r *http.Request) string {
|
|||
}
|
||||
|
||||
// Verify authorization header - http://docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-authenticating-requests.html
|
||||
func (iam *IdentityAccessManagement) doesSignatureMatch(hashedPayload string, r *http.Request) (*Identity, ErrorCode) {
|
||||
func (iam *IdentityAccessManagement) doesSignatureMatch(hashedPayload string, r *http.Request) (*Identity, s3err.ErrorCode) {
|
||||
|
||||
// Copy request.
|
||||
req := *r
|
||||
|
@ -99,33 +100,33 @@ func (iam *IdentityAccessManagement) doesSignatureMatch(hashedPayload string, r
|
|||
|
||||
// Parse signature version '4' header.
|
||||
signV4Values, err := parseSignV4(v4Auth)
|
||||
if err != ErrNone {
|
||||
if err != s3err.ErrNone {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Extract all the signed headers along with its values.
|
||||
extractedSignedHeaders, errCode := extractSignedHeaders(signV4Values.SignedHeaders, r)
|
||||
if errCode != ErrNone {
|
||||
if errCode != s3err.ErrNone {
|
||||
return nil, errCode
|
||||
}
|
||||
|
||||
// Verify if the access key id matches.
|
||||
identity, cred, found := iam.lookupByAccessKey(signV4Values.Credential.accessKey)
|
||||
if !found {
|
||||
return nil, ErrInvalidAccessKeyID
|
||||
return nil, s3err.ErrInvalidAccessKeyID
|
||||
}
|
||||
|
||||
// Extract date, if not present throw error.
|
||||
var date string
|
||||
if date = req.Header.Get(http.CanonicalHeaderKey("X-Amz-Date")); date == "" {
|
||||
if date = r.Header.Get("Date"); date == "" {
|
||||
return nil, ErrMissingDateHeader
|
||||
return nil, s3err.ErrMissingDateHeader
|
||||
}
|
||||
}
|
||||
// Parse date header.
|
||||
t, e := time.Parse(iso8601Format, date)
|
||||
if e != nil {
|
||||
return nil, ErrMalformedDate
|
||||
return nil, s3err.ErrMalformedDate
|
||||
}
|
||||
|
||||
// Query string.
|
||||
|
@ -145,11 +146,11 @@ func (iam *IdentityAccessManagement) doesSignatureMatch(hashedPayload string, r
|
|||
|
||||
// Verify if signature match.
|
||||
if !compareSignatureV4(newSignature, signV4Values.Signature) {
|
||||
return nil, ErrSignatureDoesNotMatch
|
||||
return nil, s3err.ErrSignatureDoesNotMatch
|
||||
}
|
||||
|
||||
// Return error none.
|
||||
return identity, ErrNone
|
||||
return identity, s3err.ErrNone
|
||||
}
|
||||
|
||||
// credentialHeader data type represents structured form of Credential
|
||||
|
@ -184,65 +185,65 @@ func (c credentialHeader) getScope() string {
|
|||
// Authorization: algorithm Credential=accessKeyID/credScope, \
|
||||
// SignedHeaders=signedHeaders, Signature=signature
|
||||
//
|
||||
func parseSignV4(v4Auth string) (sv signValues, aec ErrorCode) {
|
||||
func parseSignV4(v4Auth string) (sv signValues, aec s3err.ErrorCode) {
|
||||
// Replace all spaced strings, some clients can send spaced
|
||||
// parameters and some won't. So we pro-actively remove any spaces
|
||||
// to make parsing easier.
|
||||
v4Auth = strings.Replace(v4Auth, " ", "", -1)
|
||||
if v4Auth == "" {
|
||||
return sv, ErrAuthHeaderEmpty
|
||||
return sv, s3err.ErrAuthHeaderEmpty
|
||||
}
|
||||
|
||||
// Verify if the header algorithm is supported or not.
|
||||
if !strings.HasPrefix(v4Auth, signV4Algorithm) {
|
||||
return sv, ErrSignatureVersionNotSupported
|
||||
return sv, s3err.ErrSignatureVersionNotSupported
|
||||
}
|
||||
|
||||
// Strip off the Algorithm prefix.
|
||||
v4Auth = strings.TrimPrefix(v4Auth, signV4Algorithm)
|
||||
authFields := strings.Split(strings.TrimSpace(v4Auth), ",")
|
||||
if len(authFields) != 3 {
|
||||
return sv, ErrMissingFields
|
||||
return sv, s3err.ErrMissingFields
|
||||
}
|
||||
|
||||
// Initialize signature version '4' structured header.
|
||||
signV4Values := signValues{}
|
||||
|
||||
var err ErrorCode
|
||||
var err s3err.ErrorCode
|
||||
// Save credentail values.
|
||||
signV4Values.Credential, err = parseCredentialHeader(authFields[0])
|
||||
if err != ErrNone {
|
||||
if err != s3err.ErrNone {
|
||||
return sv, err
|
||||
}
|
||||
|
||||
// Save signed headers.
|
||||
signV4Values.SignedHeaders, err = parseSignedHeader(authFields[1])
|
||||
if err != ErrNone {
|
||||
if err != s3err.ErrNone {
|
||||
return sv, err
|
||||
}
|
||||
|
||||
// Save signature.
|
||||
signV4Values.Signature, err = parseSignature(authFields[2])
|
||||
if err != ErrNone {
|
||||
if err != s3err.ErrNone {
|
||||
return sv, err
|
||||
}
|
||||
|
||||
// Return the structure here.
|
||||
return signV4Values, ErrNone
|
||||
return signV4Values, s3err.ErrNone
|
||||
}
|
||||
|
||||
// parse credentialHeader string into its structured form.
|
||||
func parseCredentialHeader(credElement string) (ch credentialHeader, aec ErrorCode) {
|
||||
func parseCredentialHeader(credElement string) (ch credentialHeader, aec s3err.ErrorCode) {
|
||||
creds := strings.Split(strings.TrimSpace(credElement), "=")
|
||||
if len(creds) != 2 {
|
||||
return ch, ErrMissingFields
|
||||
return ch, s3err.ErrMissingFields
|
||||
}
|
||||
if creds[0] != "Credential" {
|
||||
return ch, ErrMissingCredTag
|
||||
return ch, s3err.ErrMissingCredTag
|
||||
}
|
||||
credElements := strings.Split(strings.TrimSpace(creds[1]), "/")
|
||||
if len(credElements) != 5 {
|
||||
return ch, ErrCredMalformed
|
||||
return ch, s3err.ErrCredMalformed
|
||||
}
|
||||
// Save access key id.
|
||||
cred := credentialHeader{
|
||||
|
@ -251,69 +252,69 @@ func parseCredentialHeader(credElement string) (ch credentialHeader, aec ErrorCo
|
|||
var e error
|
||||
cred.scope.date, e = time.Parse(yyyymmdd, credElements[1])
|
||||
if e != nil {
|
||||
return ch, ErrMalformedCredentialDate
|
||||
return ch, s3err.ErrMalformedCredentialDate
|
||||
}
|
||||
|
||||
cred.scope.region = credElements[2]
|
||||
cred.scope.service = credElements[3] // "s3"
|
||||
cred.scope.request = credElements[4] // "aws4_request"
|
||||
return cred, ErrNone
|
||||
return cred, s3err.ErrNone
|
||||
}
|
||||
|
||||
// Parse slice of signed headers from signed headers tag.
|
||||
func parseSignedHeader(signedHdrElement string) ([]string, ErrorCode) {
|
||||
func parseSignedHeader(signedHdrElement string) ([]string, s3err.ErrorCode) {
|
||||
signedHdrFields := strings.Split(strings.TrimSpace(signedHdrElement), "=")
|
||||
if len(signedHdrFields) != 2 {
|
||||
return nil, ErrMissingFields
|
||||
return nil, s3err.ErrMissingFields
|
||||
}
|
||||
if signedHdrFields[0] != "SignedHeaders" {
|
||||
return nil, ErrMissingSignHeadersTag
|
||||
return nil, s3err.ErrMissingSignHeadersTag
|
||||
}
|
||||
if signedHdrFields[1] == "" {
|
||||
return nil, ErrMissingFields
|
||||
return nil, s3err.ErrMissingFields
|
||||
}
|
||||
signedHeaders := strings.Split(signedHdrFields[1], ";")
|
||||
return signedHeaders, ErrNone
|
||||
return signedHeaders, s3err.ErrNone
|
||||
}
|
||||
|
||||
// Parse signature from signature tag.
|
||||
func parseSignature(signElement string) (string, ErrorCode) {
|
||||
func parseSignature(signElement string) (string, s3err.ErrorCode) {
|
||||
signFields := strings.Split(strings.TrimSpace(signElement), "=")
|
||||
if len(signFields) != 2 {
|
||||
return "", ErrMissingFields
|
||||
return "", s3err.ErrMissingFields
|
||||
}
|
||||
if signFields[0] != "Signature" {
|
||||
return "", ErrMissingSignTag
|
||||
return "", s3err.ErrMissingSignTag
|
||||
}
|
||||
if signFields[1] == "" {
|
||||
return "", ErrMissingFields
|
||||
return "", s3err.ErrMissingFields
|
||||
}
|
||||
signature := signFields[1]
|
||||
return signature, ErrNone
|
||||
return signature, s3err.ErrNone
|
||||
}
|
||||
|
||||
// check query headers with presigned signature
|
||||
// - http://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-query-string-auth.html
|
||||
func (iam *IdentityAccessManagement) doesPresignedSignatureMatch(hashedPayload string, r *http.Request) (*Identity, ErrorCode) {
|
||||
func (iam *IdentityAccessManagement) doesPresignedSignatureMatch(hashedPayload string, r *http.Request) (*Identity, s3err.ErrorCode) {
|
||||
|
||||
// Copy request
|
||||
req := *r
|
||||
|
||||
// Parse request query string.
|
||||
pSignValues, err := parsePreSignV4(req.URL.Query())
|
||||
if err != ErrNone {
|
||||
if err != s3err.ErrNone {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Verify if the access key id matches.
|
||||
identity, cred, found := iam.lookupByAccessKey(pSignValues.Credential.accessKey)
|
||||
if !found {
|
||||
return nil, ErrInvalidAccessKeyID
|
||||
return nil, s3err.ErrInvalidAccessKeyID
|
||||
}
|
||||
|
||||
// Extract all the signed headers along with its values.
|
||||
extractedSignedHeaders, errCode := extractSignedHeaders(pSignValues.SignedHeaders, r)
|
||||
if errCode != ErrNone {
|
||||
if errCode != s3err.ErrNone {
|
||||
return nil, errCode
|
||||
}
|
||||
// Construct new query.
|
||||
|
@ -329,11 +330,11 @@ func (iam *IdentityAccessManagement) doesPresignedSignatureMatch(hashedPayload s
|
|||
// If the host which signed the request is slightly ahead in time (by less than globalMaxSkewTime) the
|
||||
// request should still be allowed.
|
||||
if pSignValues.Date.After(now.Add(15 * time.Minute)) {
|
||||
return nil, ErrRequestNotReadyYet
|
||||
return nil, s3err.ErrRequestNotReadyYet
|
||||
}
|
||||
|
||||
if now.Sub(pSignValues.Date) > pSignValues.Expires {
|
||||
return nil, ErrExpiredPresignRequest
|
||||
return nil, s3err.ErrExpiredPresignRequest
|
||||
}
|
||||
|
||||
// Save the date and expires.
|
||||
|
@ -365,24 +366,24 @@ func (iam *IdentityAccessManagement) doesPresignedSignatureMatch(hashedPayload s
|
|||
|
||||
// Verify if date query is same.
|
||||
if req.URL.Query().Get("X-Amz-Date") != query.Get("X-Amz-Date") {
|
||||
return nil, ErrSignatureDoesNotMatch
|
||||
return nil, s3err.ErrSignatureDoesNotMatch
|
||||
}
|
||||
// Verify if expires query is same.
|
||||
if req.URL.Query().Get("X-Amz-Expires") != query.Get("X-Amz-Expires") {
|
||||
return nil, ErrSignatureDoesNotMatch
|
||||
return nil, s3err.ErrSignatureDoesNotMatch
|
||||
}
|
||||
// Verify if signed headers query is same.
|
||||
if req.URL.Query().Get("X-Amz-SignedHeaders") != query.Get("X-Amz-SignedHeaders") {
|
||||
return nil, ErrSignatureDoesNotMatch
|
||||
return nil, s3err.ErrSignatureDoesNotMatch
|
||||
}
|
||||
// Verify if credential query is same.
|
||||
if req.URL.Query().Get("X-Amz-Credential") != query.Get("X-Amz-Credential") {
|
||||
return nil, ErrSignatureDoesNotMatch
|
||||
return nil, s3err.ErrSignatureDoesNotMatch
|
||||
}
|
||||
// Verify if sha256 payload query is same.
|
||||
if req.URL.Query().Get("X-Amz-Content-Sha256") != "" {
|
||||
if req.URL.Query().Get("X-Amz-Content-Sha256") != query.Get("X-Amz-Content-Sha256") {
|
||||
return nil, ErrContentSHA256Mismatch
|
||||
return nil, s3err.ErrContentSHA256Mismatch
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -402,9 +403,9 @@ func (iam *IdentityAccessManagement) doesPresignedSignatureMatch(hashedPayload s
|
|||
|
||||
// Verify signature.
|
||||
if !compareSignatureV4(req.URL.Query().Get("X-Amz-Signature"), newSignature) {
|
||||
return nil, ErrSignatureDoesNotMatch
|
||||
return nil, s3err.ErrSignatureDoesNotMatch
|
||||
}
|
||||
return identity, ErrNone
|
||||
return identity, s3err.ErrNone
|
||||
}
|
||||
|
||||
func contains(list []string, elem string) bool {
|
||||
|
@ -433,28 +434,28 @@ type preSignValues struct {
|
|||
// querystring += &X-Amz-Signature=signature
|
||||
//
|
||||
// verifies if any of the necessary query params are missing in the presigned request.
|
||||
func doesV4PresignParamsExist(query url.Values) ErrorCode {
|
||||
func doesV4PresignParamsExist(query url.Values) s3err.ErrorCode {
|
||||
v4PresignQueryParams := []string{"X-Amz-Algorithm", "X-Amz-Credential", "X-Amz-Signature", "X-Amz-Date", "X-Amz-SignedHeaders", "X-Amz-Expires"}
|
||||
for _, v4PresignQueryParam := range v4PresignQueryParams {
|
||||
if _, ok := query[v4PresignQueryParam]; !ok {
|
||||
return ErrInvalidQueryParams
|
||||
return s3err.ErrInvalidQueryParams
|
||||
}
|
||||
}
|
||||
return ErrNone
|
||||
return s3err.ErrNone
|
||||
}
|
||||
|
||||
// Parses all the presigned signature values into separate elements.
|
||||
func parsePreSignV4(query url.Values) (psv preSignValues, aec ErrorCode) {
|
||||
var err ErrorCode
|
||||
func parsePreSignV4(query url.Values) (psv preSignValues, aec s3err.ErrorCode) {
|
||||
var err s3err.ErrorCode
|
||||
// verify whether the required query params exist.
|
||||
err = doesV4PresignParamsExist(query)
|
||||
if err != ErrNone {
|
||||
if err != s3err.ErrNone {
|
||||
return psv, err
|
||||
}
|
||||
|
||||
// Verify if the query algorithm is supported or not.
|
||||
if query.Get("X-Amz-Algorithm") != signV4Algorithm {
|
||||
return psv, ErrInvalidQuerySignatureAlgo
|
||||
return psv, s3err.ErrInvalidQuerySignatureAlgo
|
||||
}
|
||||
|
||||
// Initialize signature version '4' structured header.
|
||||
|
@ -462,7 +463,7 @@ func parsePreSignV4(query url.Values) (psv preSignValues, aec ErrorCode) {
|
|||
|
||||
// Save credential.
|
||||
preSignV4Values.Credential, err = parseCredentialHeader("Credential=" + query.Get("X-Amz-Credential"))
|
||||
if err != ErrNone {
|
||||
if err != s3err.ErrNone {
|
||||
return psv, err
|
||||
}
|
||||
|
||||
|
@ -470,47 +471,47 @@ func parsePreSignV4(query url.Values) (psv preSignValues, aec ErrorCode) {
|
|||
// Save date in native time.Time.
|
||||
preSignV4Values.Date, e = time.Parse(iso8601Format, query.Get("X-Amz-Date"))
|
||||
if e != nil {
|
||||
return psv, ErrMalformedPresignedDate
|
||||
return psv, s3err.ErrMalformedPresignedDate
|
||||
}
|
||||
|
||||
// Save expires in native time.Duration.
|
||||
preSignV4Values.Expires, e = time.ParseDuration(query.Get("X-Amz-Expires") + "s")
|
||||
if e != nil {
|
||||
return psv, ErrMalformedExpires
|
||||
return psv, s3err.ErrMalformedExpires
|
||||
}
|
||||
|
||||
if preSignV4Values.Expires < 0 {
|
||||
return psv, ErrNegativeExpires
|
||||
return psv, s3err.ErrNegativeExpires
|
||||
}
|
||||
|
||||
// Check if Expiry time is less than 7 days (value in seconds).
|
||||
if preSignV4Values.Expires.Seconds() > 604800 {
|
||||
return psv, ErrMaximumExpires
|
||||
return psv, s3err.ErrMaximumExpires
|
||||
}
|
||||
|
||||
// Save signed headers.
|
||||
preSignV4Values.SignedHeaders, err = parseSignedHeader("SignedHeaders=" + query.Get("X-Amz-SignedHeaders"))
|
||||
if err != ErrNone {
|
||||
if err != s3err.ErrNone {
|
||||
return psv, err
|
||||
}
|
||||
|
||||
// Save signature.
|
||||
preSignV4Values.Signature, err = parseSignature("Signature=" + query.Get("X-Amz-Signature"))
|
||||
if err != ErrNone {
|
||||
if err != s3err.ErrNone {
|
||||
return psv, err
|
||||
}
|
||||
|
||||
// Return structed form of signature query string.
|
||||
return preSignV4Values, ErrNone
|
||||
return preSignV4Values, s3err.ErrNone
|
||||
}
|
||||
|
||||
// extractSignedHeaders extract signed headers from Authorization header
|
||||
func extractSignedHeaders(signedHeaders []string, r *http.Request) (http.Header, ErrorCode) {
|
||||
func extractSignedHeaders(signedHeaders []string, r *http.Request) (http.Header, s3err.ErrorCode) {
|
||||
reqHeaders := r.Header
|
||||
// find whether "host" is part of list of signed headers.
|
||||
// if not return ErrUnsignedHeaders. "host" is mandatory.
|
||||
if !contains(signedHeaders, "host") {
|
||||
return nil, ErrUnsignedHeaders
|
||||
return nil, s3err.ErrUnsignedHeaders
|
||||
}
|
||||
extractedSignedHeaders := make(http.Header)
|
||||
for _, header := range signedHeaders {
|
||||
|
@ -555,10 +556,10 @@ func extractSignedHeaders(signedHeaders []string, r *http.Request) (http.Header,
|
|||
// calculation to be compatible with such clients.
|
||||
extractedSignedHeaders.Set(header, strconv.FormatInt(r.ContentLength, 10))
|
||||
default:
|
||||
return nil, ErrUnsignedHeaders
|
||||
return nil, s3err.ErrUnsignedHeaders
|
||||
}
|
||||
}
|
||||
return extractedSignedHeaders, ErrNone
|
||||
return extractedSignedHeaders, s3err.ErrNone
|
||||
}
|
||||
|
||||
// getSignedHeaders generate a string i.e alphabetically sorted, semicolon-separated list of lowercase request header names
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/chrislusf/seaweedfs/weed/s3api/s3err"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
@ -73,12 +74,12 @@ func TestIsReqAuthenticated(t *testing.T) {
|
|||
// List of test cases for validating http request authentication.
|
||||
testCases := []struct {
|
||||
req *http.Request
|
||||
s3Error ErrorCode
|
||||
s3Error s3err.ErrorCode
|
||||
}{
|
||||
// When request is unsigned, access denied is returned.
|
||||
{mustNewRequest("GET", "http://127.0.0.1:9000", 0, nil, t), ErrAccessDenied},
|
||||
{mustNewRequest("GET", "http://127.0.0.1:9000", 0, nil, t), s3err.ErrAccessDenied},
|
||||
// When request is properly signed, error is none.
|
||||
{mustNewSignedRequest("GET", "http://127.0.0.1:9000", 0, nil, t), ErrNone},
|
||||
{mustNewSignedRequest("GET", "http://127.0.0.1:9000", 0, nil, t), s3err.ErrNone},
|
||||
}
|
||||
|
||||
// Validates all testcases.
|
||||
|
@ -107,11 +108,11 @@ func TestCheckAdminRequestAuthType(t *testing.T) {
|
|||
|
||||
testCases := []struct {
|
||||
Request *http.Request
|
||||
ErrCode ErrorCode
|
||||
ErrCode s3err.ErrorCode
|
||||
}{
|
||||
{Request: mustNewRequest("GET", "http://127.0.0.1:9000", 0, nil, t), ErrCode: ErrAccessDenied},
|
||||
{Request: mustNewSignedRequest("GET", "http://127.0.0.1:9000", 0, nil, t), ErrCode: ErrNone},
|
||||
{Request: mustNewPresignedRequest("GET", "http://127.0.0.1:9000", 0, nil, t), ErrCode: ErrNone},
|
||||
{Request: mustNewRequest("GET", "http://127.0.0.1:9000", 0, nil, t), ErrCode: s3err.ErrAccessDenied},
|
||||
{Request: mustNewSignedRequest("GET", "http://127.0.0.1:9000", 0, nil, t), ErrCode: s3err.ErrNone},
|
||||
{Request: mustNewPresignedRequest("GET", "http://127.0.0.1:9000", 0, nil, t), ErrCode: s3err.ErrNone},
|
||||
}
|
||||
for i, testCase := range testCases {
|
||||
if _, s3Error := iam.reqSignatureV4Verify(testCase.Request); s3Error != testCase.ErrCode {
|
||||
|
|
|
@ -24,6 +24,7 @@ import (
|
|||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"github.com/chrislusf/seaweedfs/weed/s3api/s3err"
|
||||
"hash"
|
||||
"io"
|
||||
"net/http"
|
||||
|
@ -56,7 +57,7 @@ func getChunkSignature(secretKey string, seedSignature string, region string, da
|
|||
// - http://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-streaming.html
|
||||
// returns signature, error otherwise if the signature mismatches or any other
|
||||
// error while parsing and validating.
|
||||
func (iam *IdentityAccessManagement) calculateSeedSignature(r *http.Request) (cred *Credential, signature string, region string, date time.Time, errCode ErrorCode) {
|
||||
func (iam *IdentityAccessManagement) calculateSeedSignature(r *http.Request) (cred *Credential, signature string, region string, date time.Time, errCode s3err.ErrorCode) {
|
||||
|
||||
// Copy request.
|
||||
req := *r
|
||||
|
@ -66,7 +67,7 @@ func (iam *IdentityAccessManagement) calculateSeedSignature(r *http.Request) (cr
|
|||
|
||||
// Parse signature version '4' header.
|
||||
signV4Values, errCode := parseSignV4(v4Auth)
|
||||
if errCode != ErrNone {
|
||||
if errCode != s3err.ErrNone {
|
||||
return nil, "", "", time.Time{}, errCode
|
||||
}
|
||||
|
||||
|
@ -75,18 +76,18 @@ func (iam *IdentityAccessManagement) calculateSeedSignature(r *http.Request) (cr
|
|||
|
||||
// Payload for STREAMING signature should be 'STREAMING-AWS4-HMAC-SHA256-PAYLOAD'
|
||||
if payload != req.Header.Get("X-Amz-Content-Sha256") {
|
||||
return nil, "", "", time.Time{}, ErrContentSHA256Mismatch
|
||||
return nil, "", "", time.Time{}, s3err.ErrContentSHA256Mismatch
|
||||
}
|
||||
|
||||
// Extract all the signed headers along with its values.
|
||||
extractedSignedHeaders, errCode := extractSignedHeaders(signV4Values.SignedHeaders, r)
|
||||
if errCode != ErrNone {
|
||||
if errCode != s3err.ErrNone {
|
||||
return nil, "", "", time.Time{}, errCode
|
||||
}
|
||||
// Verify if the access key id matches.
|
||||
_, cred, found := iam.lookupByAccessKey(signV4Values.Credential.accessKey)
|
||||
if !found {
|
||||
return nil, "", "", time.Time{}, ErrInvalidAccessKeyID
|
||||
return nil, "", "", time.Time{}, s3err.ErrInvalidAccessKeyID
|
||||
}
|
||||
|
||||
// Verify if region is valid.
|
||||
|
@ -96,14 +97,14 @@ func (iam *IdentityAccessManagement) calculateSeedSignature(r *http.Request) (cr
|
|||
var dateStr string
|
||||
if dateStr = req.Header.Get(http.CanonicalHeaderKey("x-amz-date")); dateStr == "" {
|
||||
if dateStr = r.Header.Get("Date"); dateStr == "" {
|
||||
return nil, "", "", time.Time{}, ErrMissingDateHeader
|
||||
return nil, "", "", time.Time{}, s3err.ErrMissingDateHeader
|
||||
}
|
||||
}
|
||||
// Parse date header.
|
||||
var err error
|
||||
date, err = time.Parse(iso8601Format, dateStr)
|
||||
if err != nil {
|
||||
return nil, "", "", time.Time{}, ErrMalformedDate
|
||||
return nil, "", "", time.Time{}, s3err.ErrMalformedDate
|
||||
}
|
||||
|
||||
// Query string.
|
||||
|
@ -123,11 +124,11 @@ func (iam *IdentityAccessManagement) calculateSeedSignature(r *http.Request) (cr
|
|||
|
||||
// Verify if signature match.
|
||||
if !compareSignatureV4(newSignature, signV4Values.Signature) {
|
||||
return nil, "", "", time.Time{}, ErrSignatureDoesNotMatch
|
||||
return nil, "", "", time.Time{}, s3err.ErrSignatureDoesNotMatch
|
||||
}
|
||||
|
||||
// Return caculated signature.
|
||||
return cred, newSignature, region, date, ErrNone
|
||||
return cred, newSignature, region, date, s3err.ErrNone
|
||||
}
|
||||
|
||||
const maxLineLength = 4 * humanize.KiByte // assumed <= bufio.defaultBufSize 4KiB
|
||||
|
@ -141,9 +142,9 @@ var errMalformedEncoding = errors.New("malformed chunked encoding")
|
|||
// newSignV4ChunkedReader returns a new s3ChunkedReader that translates the data read from r
|
||||
// out of HTTP "chunked" format before returning it.
|
||||
// The s3ChunkedReader returns io.EOF when the final 0-length chunk is read.
|
||||
func (iam *IdentityAccessManagement) newSignV4ChunkedReader(req *http.Request) (io.ReadCloser, ErrorCode) {
|
||||
func (iam *IdentityAccessManagement) newSignV4ChunkedReader(req *http.Request) (io.ReadCloser, s3err.ErrorCode) {
|
||||
ident, seedSignature, region, seedDate, errCode := iam.calculateSeedSignature(req)
|
||||
if errCode != ErrNone {
|
||||
if errCode != s3err.ErrNone {
|
||||
return nil, errCode
|
||||
}
|
||||
return &s3ChunkedReader{
|
||||
|
@ -154,7 +155,7 @@ func (iam *IdentityAccessManagement) newSignV4ChunkedReader(req *http.Request) (
|
|||
region: region,
|
||||
chunkSHA256Writer: sha256.New(),
|
||||
state: readChunkHeader,
|
||||
}, ErrNone
|
||||
}, s3err.ErrNone
|
||||
}
|
||||
|
||||
// Represents the overall state that is required for decoding a
|
||||
|
|
|
@ -3,6 +3,7 @@ package s3api
|
|||
import (
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"github.com/chrislusf/seaweedfs/weed/s3api/s3err"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
@ -22,7 +23,7 @@ type InitiateMultipartUploadResult struct {
|
|||
s3.CreateMultipartUploadOutput
|
||||
}
|
||||
|
||||
func (s3a *S3ApiServer) createMultipartUpload(input *s3.CreateMultipartUploadInput) (output *InitiateMultipartUploadResult, code ErrorCode) {
|
||||
func (s3a *S3ApiServer) createMultipartUpload(input *s3.CreateMultipartUploadInput) (output *InitiateMultipartUploadResult, code s3err.ErrorCode) {
|
||||
uploadId, _ := uuid.NewRandom()
|
||||
uploadIdString := uploadId.String()
|
||||
|
||||
|
@ -33,7 +34,7 @@ func (s3a *S3ApiServer) createMultipartUpload(input *s3.CreateMultipartUploadInp
|
|||
entry.Extended["key"] = []byte(*input.Key)
|
||||
}); err != nil {
|
||||
glog.Errorf("NewMultipartUpload error: %v", err)
|
||||
return nil, ErrInternalError
|
||||
return nil, s3err.ErrInternalError
|
||||
}
|
||||
|
||||
output = &InitiateMultipartUploadResult{
|
||||
|
@ -52,14 +53,14 @@ type CompleteMultipartUploadResult struct {
|
|||
s3.CompleteMultipartUploadOutput
|
||||
}
|
||||
|
||||
func (s3a *S3ApiServer) completeMultipartUpload(input *s3.CompleteMultipartUploadInput) (output *CompleteMultipartUploadResult, code ErrorCode) {
|
||||
func (s3a *S3ApiServer) completeMultipartUpload(input *s3.CompleteMultipartUploadInput) (output *CompleteMultipartUploadResult, code s3err.ErrorCode) {
|
||||
|
||||
uploadDirectory := s3a.genUploadsFolder(*input.Bucket) + "/" + *input.UploadId
|
||||
|
||||
entries, _, err := s3a.list(uploadDirectory, "", "", false, 0)
|
||||
if err != nil || len(entries) == 0 {
|
||||
glog.Errorf("completeMultipartUpload %s %s error: %v, entries:%d", *input.Bucket, *input.UploadId, err, len(entries))
|
||||
return nil, ErrNoSuchUpload
|
||||
return nil, s3err.ErrNoSuchUpload
|
||||
}
|
||||
|
||||
var finalParts []*filer_pb.FileChunk
|
||||
|
@ -101,7 +102,7 @@ func (s3a *S3ApiServer) completeMultipartUpload(input *s3.CompleteMultipartUploa
|
|||
|
||||
if err != nil {
|
||||
glog.Errorf("completeMultipartUpload %s/%s error: %v", dirName, entryName, err)
|
||||
return nil, ErrInternalError
|
||||
return nil, s3err.ErrInternalError
|
||||
}
|
||||
|
||||
output = &CompleteMultipartUploadResult{
|
||||
|
@ -120,22 +121,22 @@ func (s3a *S3ApiServer) completeMultipartUpload(input *s3.CompleteMultipartUploa
|
|||
return
|
||||
}
|
||||
|
||||
func (s3a *S3ApiServer) abortMultipartUpload(input *s3.AbortMultipartUploadInput) (output *s3.AbortMultipartUploadOutput, code ErrorCode) {
|
||||
func (s3a *S3ApiServer) abortMultipartUpload(input *s3.AbortMultipartUploadInput) (output *s3.AbortMultipartUploadOutput, code s3err.ErrorCode) {
|
||||
|
||||
exists, err := s3a.exists(s3a.genUploadsFolder(*input.Bucket), *input.UploadId, true)
|
||||
if err != nil {
|
||||
glog.V(1).Infof("bucket %s abort upload %s: %v", *input.Bucket, *input.UploadId, err)
|
||||
return nil, ErrNoSuchUpload
|
||||
return nil, s3err.ErrNoSuchUpload
|
||||
}
|
||||
if exists {
|
||||
err = s3a.rm(s3a.genUploadsFolder(*input.Bucket), *input.UploadId, true, true)
|
||||
}
|
||||
if err != nil {
|
||||
glog.V(1).Infof("bucket %s remove upload %s: %v", *input.Bucket, *input.UploadId, err)
|
||||
return nil, ErrInternalError
|
||||
return nil, s3err.ErrInternalError
|
||||
}
|
||||
|
||||
return &s3.AbortMultipartUploadOutput{}, ErrNone
|
||||
return &s3.AbortMultipartUploadOutput{}, s3err.ErrNone
|
||||
}
|
||||
|
||||
type ListMultipartUploadsResult struct {
|
||||
|
@ -155,7 +156,7 @@ type ListMultipartUploadsResult struct {
|
|||
Upload []*s3.MultipartUpload `locationName:"Upload" type:"list" flattened:"true"`
|
||||
}
|
||||
|
||||
func (s3a *S3ApiServer) listMultipartUploads(input *s3.ListMultipartUploadsInput) (output *ListMultipartUploadsResult, code ErrorCode) {
|
||||
func (s3a *S3ApiServer) listMultipartUploads(input *s3.ListMultipartUploadsInput) (output *ListMultipartUploadsResult, code s3err.ErrorCode) {
|
||||
// https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListMultipartUploads.html
|
||||
|
||||
output = &ListMultipartUploadsResult{
|
||||
|
@ -205,7 +206,7 @@ type ListPartsResult struct {
|
|||
UploadId *string `type:"string"`
|
||||
}
|
||||
|
||||
func (s3a *S3ApiServer) listObjectParts(input *s3.ListPartsInput) (output *ListPartsResult, code ErrorCode) {
|
||||
func (s3a *S3ApiServer) listObjectParts(input *s3.ListPartsInput) (output *ListPartsResult, code s3err.ErrorCode) {
|
||||
// https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListParts.html
|
||||
|
||||
output = &ListPartsResult{
|
||||
|
@ -220,7 +221,7 @@ func (s3a *S3ApiServer) listObjectParts(input *s3.ListPartsInput) (output *ListP
|
|||
entries, isLast, err := s3a.list(s3a.genUploadsFolder(*input.Bucket)+"/"+*input.UploadId, "", fmt.Sprintf("%04d.part", *input.PartNumberMarker), false, uint32(*input.MaxParts))
|
||||
if err != nil {
|
||||
glog.Errorf("listObjectParts %s %s error: %v", *input.Bucket, *input.UploadId, err)
|
||||
return nil, ErrNoSuchUpload
|
||||
return nil, s3err.ErrNoSuchUpload
|
||||
}
|
||||
|
||||
output.IsTruncated = aws.Bool(!isLast)
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"context"
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"github.com/chrislusf/seaweedfs/weed/s3api/s3err"
|
||||
"math"
|
||||
"net/http"
|
||||
"time"
|
||||
|
@ -28,7 +29,7 @@ func (s3a *S3ApiServer) ListBucketsHandler(w http.ResponseWriter, r *http.Reques
|
|||
entries, _, err := s3a.list(s3a.option.BucketsPath, "", "", false, math.MaxInt32)
|
||||
|
||||
if err != nil {
|
||||
writeErrorResponse(w, ErrInternalError, r.URL)
|
||||
writeErrorResponse(w, s3err.ErrInternalError, r.URL)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -59,7 +60,7 @@ func (s3a *S3ApiServer) PutBucketHandler(w http.ResponseWriter, r *http.Request)
|
|||
|
||||
// create the folder for bucket, but lazily create actual collection
|
||||
if err := s3a.mkdir(s3a.option.BucketsPath, bucket, nil); err != nil {
|
||||
writeErrorResponse(w, ErrInternalError, r.URL)
|
||||
writeErrorResponse(w, s3err.ErrInternalError, r.URL)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -88,7 +89,7 @@ func (s3a *S3ApiServer) DeleteBucketHandler(w http.ResponseWriter, r *http.Reque
|
|||
err = s3a.rm(s3a.option.BucketsPath, bucket, false, true)
|
||||
|
||||
if err != nil {
|
||||
writeErrorResponse(w, ErrInternalError, r.URL)
|
||||
writeErrorResponse(w, s3err.ErrInternalError, r.URL)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -118,7 +119,7 @@ func (s3a *S3ApiServer) HeadBucketHandler(w http.ResponseWriter, r *http.Request
|
|||
})
|
||||
|
||||
if err != nil {
|
||||
writeErrorResponse(w, ErrNoSuchBucket, r.URL)
|
||||
writeErrorResponse(w, s3err.ErrNoSuchBucket, r.URL)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"encoding/base64"
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"github.com/chrislusf/seaweedfs/weed/s3api/s3err"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
|
@ -56,18 +57,18 @@ func (s3a *S3ApiServer) AdjustedUrl(hostAndPort string) string {
|
|||
// If none of the http routes match respond with MethodNotAllowed
|
||||
func notFoundHandler(w http.ResponseWriter, r *http.Request) {
|
||||
glog.V(0).Infof("unsupported %s %s", r.Method, r.RequestURI)
|
||||
writeErrorResponse(w, ErrMethodNotAllowed, r.URL)
|
||||
writeErrorResponse(w, s3err.ErrMethodNotAllowed, r.URL)
|
||||
}
|
||||
|
||||
func writeErrorResponse(w http.ResponseWriter, errorCode ErrorCode, reqURL *url.URL) {
|
||||
apiError := getAPIError(errorCode)
|
||||
func writeErrorResponse(w http.ResponseWriter, errorCode s3err.ErrorCode, reqURL *url.URL) {
|
||||
apiError := s3err.GetAPIError(errorCode)
|
||||
errorResponse := getRESTErrorResponse(apiError, reqURL.Path)
|
||||
encodedErrorResponse := encodeResponse(errorResponse)
|
||||
writeResponse(w, apiError.HTTPStatusCode, encodedErrorResponse, mimeXML)
|
||||
}
|
||||
|
||||
func getRESTErrorResponse(err APIError, resource string) RESTErrorResponse {
|
||||
return RESTErrorResponse{
|
||||
func getRESTErrorResponse(err s3err.APIError, resource string) s3err.RESTErrorResponse {
|
||||
return s3err.RESTErrorResponse{
|
||||
Code: err.Code,
|
||||
Message: err.Description,
|
||||
Resource: resource,
|
||||
|
|
|
@ -2,6 +2,7 @@ package s3api
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/chrislusf/seaweedfs/weed/s3api/s3err"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
|
@ -25,12 +26,12 @@ func (s3a *S3ApiServer) CopyObjectHandler(w http.ResponseWriter, r *http.Request
|
|||
srcBucket, srcObject := pathToBucketAndObject(cpSrcPath)
|
||||
// If source object is empty or bucket is empty, reply back invalid copy source.
|
||||
if srcObject == "" || srcBucket == "" {
|
||||
writeErrorResponse(w, ErrInvalidCopySource, r.URL)
|
||||
writeErrorResponse(w, s3err.ErrInvalidCopySource, r.URL)
|
||||
return
|
||||
}
|
||||
|
||||
if srcBucket == dstBucket && srcObject == dstObject {
|
||||
writeErrorResponse(w, ErrInvalidCopySource, r.URL)
|
||||
writeErrorResponse(w, s3err.ErrInvalidCopySource, r.URL)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -41,14 +42,14 @@ func (s3a *S3ApiServer) CopyObjectHandler(w http.ResponseWriter, r *http.Request
|
|||
|
||||
_, _, resp, err := util.DownloadFile(srcUrl)
|
||||
if err != nil {
|
||||
writeErrorResponse(w, ErrInvalidCopySource, r.URL)
|
||||
writeErrorResponse(w, s3err.ErrInvalidCopySource, r.URL)
|
||||
return
|
||||
}
|
||||
defer util.CloseResponse(resp)
|
||||
|
||||
etag, errCode := s3a.putToFiler(r, dstUrl, resp.Body)
|
||||
|
||||
if errCode != ErrNone {
|
||||
if errCode != s3err.ErrNone {
|
||||
writeErrorResponse(w, errCode, r.URL)
|
||||
return
|
||||
}
|
||||
|
@ -93,7 +94,7 @@ func (s3a *S3ApiServer) CopyObjectPartHandler(w http.ResponseWriter, r *http.Req
|
|||
srcBucket, srcObject := pathToBucketAndObject(cpSrcPath)
|
||||
// If source object is empty or bucket is empty, reply back invalid copy source.
|
||||
if srcObject == "" || srcBucket == "" {
|
||||
writeErrorResponse(w, ErrInvalidCopySource, r.URL)
|
||||
writeErrorResponse(w, s3err.ErrInvalidCopySource, r.URL)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -102,13 +103,13 @@ func (s3a *S3ApiServer) CopyObjectPartHandler(w http.ResponseWriter, r *http.Req
|
|||
|
||||
partID, err := strconv.Atoi(partIDString)
|
||||
if err != nil {
|
||||
writeErrorResponse(w, ErrInvalidPart, r.URL)
|
||||
writeErrorResponse(w, s3err.ErrInvalidPart, r.URL)
|
||||
return
|
||||
}
|
||||
|
||||
// check partID with maximum part ID for multipart objects
|
||||
if partID > globalMaxPartID {
|
||||
writeErrorResponse(w, ErrInvalidMaxParts, r.URL)
|
||||
writeErrorResponse(w, s3err.ErrInvalidMaxParts, r.URL)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -121,14 +122,14 @@ func (s3a *S3ApiServer) CopyObjectPartHandler(w http.ResponseWriter, r *http.Req
|
|||
|
||||
dataReader, err := util.ReadUrlAsReaderCloser(srcUrl, rangeHeader)
|
||||
if err != nil {
|
||||
writeErrorResponse(w, ErrInvalidCopySource, r.URL)
|
||||
writeErrorResponse(w, s3err.ErrInvalidCopySource, r.URL)
|
||||
return
|
||||
}
|
||||
defer dataReader.Close()
|
||||
|
||||
etag, errCode := s3a.putToFiler(r, dstUrl, dataReader)
|
||||
|
||||
if errCode != ErrNone {
|
||||
if errCode != s3err.ErrNone {
|
||||
writeErrorResponse(w, errCode, r.URL)
|
||||
return
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"encoding/json"
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"github.com/chrislusf/seaweedfs/weed/s3api/s3err"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
@ -36,14 +37,14 @@ func (s3a *S3ApiServer) PutObjectHandler(w http.ResponseWriter, r *http.Request)
|
|||
|
||||
_, err := validateContentMd5(r.Header)
|
||||
if err != nil {
|
||||
writeErrorResponse(w, ErrInvalidDigest, r.URL)
|
||||
writeErrorResponse(w, s3err.ErrInvalidDigest, r.URL)
|
||||
return
|
||||
}
|
||||
|
||||
dataReader := r.Body
|
||||
if s3a.iam.isEnabled() {
|
||||
rAuthType := getRequestAuthType(r)
|
||||
var s3ErrCode ErrorCode
|
||||
var s3ErrCode s3err.ErrorCode
|
||||
switch rAuthType {
|
||||
case authTypeStreamingSigned:
|
||||
dataReader, s3ErrCode = s3a.iam.newSignV4ChunkedReader(r)
|
||||
|
@ -52,7 +53,7 @@ func (s3a *S3ApiServer) PutObjectHandler(w http.ResponseWriter, r *http.Request)
|
|||
case authTypePresigned, authTypeSigned:
|
||||
_, s3ErrCode = s3a.iam.reqSignatureV4Verify(r)
|
||||
}
|
||||
if s3ErrCode != ErrNone {
|
||||
if s3ErrCode != s3err.ErrNone {
|
||||
writeErrorResponse(w, s3ErrCode, r.URL)
|
||||
return
|
||||
}
|
||||
|
@ -61,7 +62,7 @@ func (s3a *S3ApiServer) PutObjectHandler(w http.ResponseWriter, r *http.Request)
|
|||
|
||||
if strings.HasSuffix(object, "/") {
|
||||
if err := s3a.mkdir(s3a.option.BucketsPath, bucket+object, nil); err != nil {
|
||||
writeErrorResponse(w, ErrInternalError, r.URL)
|
||||
writeErrorResponse(w, s3err.ErrInternalError, r.URL)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
|
@ -69,7 +70,7 @@ func (s3a *S3ApiServer) PutObjectHandler(w http.ResponseWriter, r *http.Request)
|
|||
|
||||
etag, errCode := s3a.putToFiler(r, uploadUrl, dataReader)
|
||||
|
||||
if errCode != ErrNone {
|
||||
if errCode != s3err.ErrNone {
|
||||
writeErrorResponse(w, errCode, r.URL)
|
||||
return
|
||||
}
|
||||
|
@ -85,7 +86,7 @@ func (s3a *S3ApiServer) GetObjectHandler(w http.ResponseWriter, r *http.Request)
|
|||
bucket, object := getBucketAndObject(r)
|
||||
|
||||
if strings.HasSuffix(r.URL.Path, "/") {
|
||||
writeErrorResponse(w, ErrNotImplemented, r.URL)
|
||||
writeErrorResponse(w, s3err.ErrNotImplemented, r.URL)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -161,13 +162,13 @@ func (s3a *S3ApiServer) DeleteMultipleObjectsHandler(w http.ResponseWriter, r *h
|
|||
|
||||
deleteXMLBytes, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
writeErrorResponse(w, ErrInternalError, r.URL)
|
||||
writeErrorResponse(w, s3err.ErrInternalError, r.URL)
|
||||
return
|
||||
}
|
||||
|
||||
deleteObjects := &DeleteObjectsRequest{}
|
||||
if err := xml.Unmarshal(deleteXMLBytes, deleteObjects); err != nil {
|
||||
writeErrorResponse(w, ErrMalformedXML, r.URL)
|
||||
writeErrorResponse(w, s3err.ErrMalformedXML, r.URL)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -217,7 +218,7 @@ func (s3a *S3ApiServer) proxyToFiler(w http.ResponseWriter, r *http.Request, des
|
|||
|
||||
if err != nil {
|
||||
glog.Errorf("NewRequest %s: %v", destUrl, err)
|
||||
writeErrorResponse(w, ErrInternalError, r.URL)
|
||||
writeErrorResponse(w, s3err.ErrInternalError, r.URL)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -233,13 +234,13 @@ func (s3a *S3ApiServer) proxyToFiler(w http.ResponseWriter, r *http.Request, des
|
|||
resp, postErr := client.Do(proxyReq)
|
||||
|
||||
if resp.ContentLength == -1 {
|
||||
writeErrorResponse(w, ErrNoSuchKey, r.URL)
|
||||
writeErrorResponse(w, s3err.ErrNoSuchKey, r.URL)
|
||||
return
|
||||
}
|
||||
|
||||
if postErr != nil {
|
||||
glog.Errorf("post to filer: %v", postErr)
|
||||
writeErrorResponse(w, ErrInternalError, r.URL)
|
||||
writeErrorResponse(w, s3err.ErrInternalError, r.URL)
|
||||
return
|
||||
}
|
||||
defer util.CloseResponse(resp)
|
||||
|
@ -255,7 +256,7 @@ func passThroughResponse(proxyResponse *http.Response, w http.ResponseWriter) {
|
|||
io.Copy(w, proxyResponse.Body)
|
||||
}
|
||||
|
||||
func (s3a *S3ApiServer) putToFiler(r *http.Request, uploadUrl string, dataReader io.Reader) (etag string, code ErrorCode) {
|
||||
func (s3a *S3ApiServer) putToFiler(r *http.Request, uploadUrl string, dataReader io.Reader) (etag string, code s3err.ErrorCode) {
|
||||
|
||||
hash := md5.New()
|
||||
var body = io.TeeReader(dataReader, hash)
|
||||
|
@ -264,7 +265,7 @@ func (s3a *S3ApiServer) putToFiler(r *http.Request, uploadUrl string, dataReader
|
|||
|
||||
if err != nil {
|
||||
glog.Errorf("NewRequest %s: %v", uploadUrl, err)
|
||||
return "", ErrInternalError
|
||||
return "", s3err.ErrInternalError
|
||||
}
|
||||
|
||||
proxyReq.Header.Set("Host", s3a.option.Filer)
|
||||
|
@ -280,7 +281,7 @@ func (s3a *S3ApiServer) putToFiler(r *http.Request, uploadUrl string, dataReader
|
|||
|
||||
if postErr != nil {
|
||||
glog.Errorf("post to filer: %v", postErr)
|
||||
return "", ErrInternalError
|
||||
return "", s3err.ErrInternalError
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
|
@ -289,20 +290,20 @@ func (s3a *S3ApiServer) putToFiler(r *http.Request, uploadUrl string, dataReader
|
|||
resp_body, ra_err := ioutil.ReadAll(resp.Body)
|
||||
if ra_err != nil {
|
||||
glog.Errorf("upload to filer response read: %v", ra_err)
|
||||
return etag, ErrInternalError
|
||||
return etag, s3err.ErrInternalError
|
||||
}
|
||||
var ret weed_server.FilerPostResult
|
||||
unmarshal_err := json.Unmarshal(resp_body, &ret)
|
||||
if unmarshal_err != nil {
|
||||
glog.Errorf("failing to read upload to %s : %v", uploadUrl, string(resp_body))
|
||||
return "", ErrInternalError
|
||||
return "", s3err.ErrInternalError
|
||||
}
|
||||
if ret.Error != "" {
|
||||
glog.Errorf("upload to filer error: %v", ret.Error)
|
||||
return "", ErrInternalError
|
||||
return "", s3err.ErrInternalError
|
||||
}
|
||||
|
||||
return etag, ErrNone
|
||||
return etag, s3err.ErrNone
|
||||
}
|
||||
|
||||
func setEtag(w http.ResponseWriter, etag string) {
|
||||
|
|
|
@ -2,6 +2,7 @@ package s3api
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/chrislusf/seaweedfs/weed/s3api/s3err"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
|
@ -27,7 +28,7 @@ func (s3a *S3ApiServer) NewMultipartUploadHandler(w http.ResponseWriter, r *http
|
|||
Key: objectKey(aws.String(object)),
|
||||
})
|
||||
|
||||
if errCode != ErrNone {
|
||||
if errCode != s3err.ErrNone {
|
||||
writeErrorResponse(w, errCode, r.URL)
|
||||
return
|
||||
}
|
||||
|
@ -53,7 +54,7 @@ func (s3a *S3ApiServer) CompleteMultipartUploadHandler(w http.ResponseWriter, r
|
|||
|
||||
// println("CompleteMultipartUploadHandler", string(encodeResponse(response)), errCode)
|
||||
|
||||
if errCode != ErrNone {
|
||||
if errCode != s3err.ErrNone {
|
||||
writeErrorResponse(w, errCode, r.URL)
|
||||
return
|
||||
}
|
||||
|
@ -75,7 +76,7 @@ func (s3a *S3ApiServer) AbortMultipartUploadHandler(w http.ResponseWriter, r *ht
|
|||
UploadId: aws.String(uploadID),
|
||||
})
|
||||
|
||||
if errCode != ErrNone {
|
||||
if errCode != s3err.ErrNone {
|
||||
writeErrorResponse(w, errCode, r.URL)
|
||||
return
|
||||
}
|
||||
|
@ -92,13 +93,13 @@ func (s3a *S3ApiServer) ListMultipartUploadsHandler(w http.ResponseWriter, r *ht
|
|||
|
||||
prefix, keyMarker, uploadIDMarker, delimiter, maxUploads, encodingType := getBucketMultipartResources(r.URL.Query())
|
||||
if maxUploads < 0 {
|
||||
writeErrorResponse(w, ErrInvalidMaxUploads, r.URL)
|
||||
writeErrorResponse(w, s3err.ErrInvalidMaxUploads, r.URL)
|
||||
return
|
||||
}
|
||||
if keyMarker != "" {
|
||||
// Marker not common with prefix is not implemented.
|
||||
if !strings.HasPrefix(keyMarker, prefix) {
|
||||
writeErrorResponse(w, ErrNotImplemented, r.URL)
|
||||
writeErrorResponse(w, s3err.ErrNotImplemented, r.URL)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
@ -113,7 +114,7 @@ func (s3a *S3ApiServer) ListMultipartUploadsHandler(w http.ResponseWriter, r *ht
|
|||
UploadIdMarker: aws.String(uploadIDMarker),
|
||||
})
|
||||
|
||||
if errCode != ErrNone {
|
||||
if errCode != s3err.ErrNone {
|
||||
writeErrorResponse(w, errCode, r.URL)
|
||||
return
|
||||
}
|
||||
|
@ -130,11 +131,11 @@ func (s3a *S3ApiServer) ListObjectPartsHandler(w http.ResponseWriter, r *http.Re
|
|||
|
||||
uploadID, partNumberMarker, maxParts, _ := getObjectResources(r.URL.Query())
|
||||
if partNumberMarker < 0 {
|
||||
writeErrorResponse(w, ErrInvalidPartNumberMarker, r.URL)
|
||||
writeErrorResponse(w, s3err.ErrInvalidPartNumberMarker, r.URL)
|
||||
return
|
||||
}
|
||||
if maxParts < 0 {
|
||||
writeErrorResponse(w, ErrInvalidMaxParts, r.URL)
|
||||
writeErrorResponse(w, s3err.ErrInvalidMaxParts, r.URL)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -146,7 +147,7 @@ func (s3a *S3ApiServer) ListObjectPartsHandler(w http.ResponseWriter, r *http.Re
|
|||
UploadId: aws.String(uploadID),
|
||||
})
|
||||
|
||||
if errCode != ErrNone {
|
||||
if errCode != s3err.ErrNone {
|
||||
writeErrorResponse(w, errCode, r.URL)
|
||||
return
|
||||
}
|
||||
|
@ -164,25 +165,25 @@ func (s3a *S3ApiServer) PutObjectPartHandler(w http.ResponseWriter, r *http.Requ
|
|||
uploadID := r.URL.Query().Get("uploadId")
|
||||
exists, err := s3a.exists(s3a.genUploadsFolder(bucket), uploadID, true)
|
||||
if !exists {
|
||||
writeErrorResponse(w, ErrNoSuchUpload, r.URL)
|
||||
writeErrorResponse(w, s3err.ErrNoSuchUpload, r.URL)
|
||||
return
|
||||
}
|
||||
|
||||
partIDString := r.URL.Query().Get("partNumber")
|
||||
partID, err := strconv.Atoi(partIDString)
|
||||
if err != nil {
|
||||
writeErrorResponse(w, ErrInvalidPart, r.URL)
|
||||
writeErrorResponse(w, s3err.ErrInvalidPart, r.URL)
|
||||
return
|
||||
}
|
||||
if partID > globalMaxPartID {
|
||||
writeErrorResponse(w, ErrInvalidMaxParts, r.URL)
|
||||
writeErrorResponse(w, s3err.ErrInvalidMaxParts, r.URL)
|
||||
return
|
||||
}
|
||||
|
||||
dataReader := r.Body
|
||||
if s3a.iam.isEnabled() {
|
||||
rAuthType := getRequestAuthType(r)
|
||||
var s3ErrCode ErrorCode
|
||||
var s3ErrCode s3err.ErrorCode
|
||||
switch rAuthType {
|
||||
case authTypeStreamingSigned:
|
||||
dataReader, s3ErrCode = s3a.iam.newSignV4ChunkedReader(r)
|
||||
|
@ -191,7 +192,7 @@ func (s3a *S3ApiServer) PutObjectPartHandler(w http.ResponseWriter, r *http.Requ
|
|||
case authTypePresigned, authTypeSigned:
|
||||
_, s3ErrCode = s3a.iam.reqSignatureV4Verify(r)
|
||||
}
|
||||
if s3ErrCode != ErrNone {
|
||||
if s3ErrCode != s3err.ErrNone {
|
||||
writeErrorResponse(w, s3ErrCode, r.URL)
|
||||
return
|
||||
}
|
||||
|
@ -203,7 +204,7 @@ func (s3a *S3ApiServer) PutObjectPartHandler(w http.ResponseWriter, r *http.Requ
|
|||
|
||||
etag, errCode := s3a.putToFiler(r, uploadUrl, dataReader)
|
||||
|
||||
if errCode != ErrNone {
|
||||
if errCode != s3err.ErrNone {
|
||||
writeErrorResponse(w, errCode, r.URL)
|
||||
return
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"context"
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"github.com/chrislusf/seaweedfs/weed/s3api/s3err"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
@ -41,11 +42,11 @@ func (s3a *S3ApiServer) ListObjectsV2Handler(w http.ResponseWriter, r *http.Requ
|
|||
originalPrefix, continuationToken, startAfter, delimiter, _, maxKeys := getListObjectsV2Args(r.URL.Query())
|
||||
|
||||
if maxKeys < 0 {
|
||||
writeErrorResponse(w, ErrInvalidMaxKeys, r.URL)
|
||||
writeErrorResponse(w, s3err.ErrInvalidMaxKeys, r.URL)
|
||||
return
|
||||
}
|
||||
if delimiter != "" && delimiter != "/" {
|
||||
writeErrorResponse(w, ErrNotImplemented, r.URL)
|
||||
writeErrorResponse(w, s3err.ErrNotImplemented, r.URL)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -57,7 +58,7 @@ func (s3a *S3ApiServer) ListObjectsV2Handler(w http.ResponseWriter, r *http.Requ
|
|||
response, err := s3a.listFilerEntries(bucket, originalPrefix, maxKeys, marker, delimiter)
|
||||
|
||||
if err != nil {
|
||||
writeErrorResponse(w, ErrInternalError, r.URL)
|
||||
writeErrorResponse(w, s3err.ErrInternalError, r.URL)
|
||||
return
|
||||
}
|
||||
responseV2 := &ListBucketResultV2{
|
||||
|
@ -88,18 +89,18 @@ func (s3a *S3ApiServer) ListObjectsV1Handler(w http.ResponseWriter, r *http.Requ
|
|||
originalPrefix, marker, delimiter, maxKeys := getListObjectsV1Args(r.URL.Query())
|
||||
|
||||
if maxKeys < 0 {
|
||||
writeErrorResponse(w, ErrInvalidMaxKeys, r.URL)
|
||||
writeErrorResponse(w, s3err.ErrInvalidMaxKeys, r.URL)
|
||||
return
|
||||
}
|
||||
if delimiter != "" && delimiter != "/" {
|
||||
writeErrorResponse(w, ErrNotImplemented, r.URL)
|
||||
writeErrorResponse(w, s3err.ErrNotImplemented, r.URL)
|
||||
return
|
||||
}
|
||||
|
||||
response, err := s3a.listFilerEntries(bucket, originalPrefix, maxKeys, marker, delimiter)
|
||||
|
||||
if err != nil {
|
||||
writeErrorResponse(w, ErrInternalError, r.URL)
|
||||
writeErrorResponse(w, s3err.ErrInternalError, r.URL)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package s3api
|
||||
package s3err
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
|
@ -296,7 +296,7 @@ var errorCodeResponse = map[ErrorCode]APIError{
|
|||
},
|
||||
}
|
||||
|
||||
// getAPIError provides API Error for input API error code.
|
||||
func getAPIError(code ErrorCode) APIError {
|
||||
// GetAPIError provides API Error for input API error code.
|
||||
func GetAPIError(code ErrorCode) APIError {
|
||||
return errorCodeResponse[code]
|
||||
}
|
Loading…
Reference in a new issue