You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

284 lines
7.9 KiB

3 years ago
7 years ago
7 years ago
7 years ago
4 years ago
6 years ago
4 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
4 years ago
5 years ago
4 years ago
4 years ago
4 years ago
6 years ago
4 years ago
5 years ago
4 years ago
4 years ago
4 years ago
7 years ago
5 years ago
7 years ago
4 years ago
4 years ago
4 years ago
7 years ago
7 years ago
3 years ago
  1. package s3api
  2. import (
  3. "context"
  4. "encoding/xml"
  5. "fmt"
  6. "github.com/chrislusf/seaweedfs/weed/filer"
  7. "github.com/chrislusf/seaweedfs/weed/s3api/s3_constants"
  8. "math"
  9. "net/http"
  10. "time"
  11. xhttp "github.com/chrislusf/seaweedfs/weed/s3api/http"
  12. "github.com/chrislusf/seaweedfs/weed/s3api/s3err"
  13. "github.com/aws/aws-sdk-go/aws"
  14. "github.com/aws/aws-sdk-go/service/s3"
  15. "github.com/chrislusf/seaweedfs/weed/glog"
  16. "github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
  17. )
  18. type ListAllMyBucketsResult struct {
  19. XMLName xml.Name `xml:"http://s3.amazonaws.com/doc/2006-03-01/ ListAllMyBucketsResult"`
  20. Owner *s3.Owner
  21. Buckets []*s3.Bucket `xml:"Buckets>Bucket"`
  22. }
  23. func (s3a *S3ApiServer) ListBucketsHandler(w http.ResponseWriter, r *http.Request) {
  24. glog.V(3).Infof("ListBucketsHandler")
  25. var identity *Identity
  26. var s3Err s3err.ErrorCode
  27. if s3a.iam.isEnabled() {
  28. identity, s3Err = s3a.iam.authUser(r)
  29. if s3Err != s3err.ErrNone {
  30. s3err.WriteErrorResponse(w, s3Err, r)
  31. return
  32. }
  33. }
  34. var response ListAllMyBucketsResult
  35. entries, _, err := s3a.list(s3a.option.BucketsPath, "", "", false, math.MaxInt32)
  36. if err != nil {
  37. s3err.WriteErrorResponse(w, s3err.ErrInternalError, r)
  38. return
  39. }
  40. identityId := r.Header.Get(xhttp.AmzIdentityId)
  41. var buckets []*s3.Bucket
  42. for _, entry := range entries {
  43. if entry.IsDirectory {
  44. if identity != nil && !identity.canDo(s3_constants.ACTION_LIST, entry.Name) {
  45. continue
  46. }
  47. buckets = append(buckets, &s3.Bucket{
  48. Name: aws.String(entry.Name),
  49. CreationDate: aws.Time(time.Unix(entry.Attributes.Crtime, 0).UTC()),
  50. })
  51. }
  52. }
  53. response = ListAllMyBucketsResult{
  54. Owner: &s3.Owner{
  55. ID: aws.String(identityId),
  56. DisplayName: aws.String(identityId),
  57. },
  58. Buckets: buckets,
  59. }
  60. writeSuccessResponseXML(w, response)
  61. }
  62. func (s3a *S3ApiServer) PutBucketHandler(w http.ResponseWriter, r *http.Request) {
  63. bucket, _ := getBucketAndObject(r)
  64. glog.V(3).Infof("PutBucketHandler %s", bucket)
  65. // avoid duplicated buckets
  66. errCode := s3err.ErrNone
  67. if err := s3a.WithFilerClient(func(client filer_pb.SeaweedFilerClient) error {
  68. if resp, err := client.CollectionList(context.Background(), &filer_pb.CollectionListRequest{
  69. IncludeEcVolumes: true,
  70. IncludeNormalVolumes: true,
  71. }); err != nil {
  72. glog.Errorf("list collection: %v", err)
  73. return fmt.Errorf("list collections: %v", err)
  74. } else {
  75. for _, c := range resp.Collections {
  76. if bucket == c.Name {
  77. errCode = s3err.ErrBucketAlreadyExists
  78. break
  79. }
  80. }
  81. }
  82. return nil
  83. }); err != nil {
  84. s3err.WriteErrorResponse(w, s3err.ErrInternalError, r)
  85. return
  86. }
  87. if exist, err := s3a.exists(s3a.option.BucketsPath, bucket, true); err == nil && exist {
  88. errCode = s3err.ErrBucketAlreadyExists
  89. }
  90. if errCode != s3err.ErrNone {
  91. s3err.WriteErrorResponse(w, errCode, r)
  92. return
  93. }
  94. fn := func(entry *filer_pb.Entry) {
  95. if identityId := r.Header.Get(xhttp.AmzIdentityId); identityId != "" {
  96. if entry.Extended == nil {
  97. entry.Extended = make(map[string][]byte)
  98. }
  99. entry.Extended[xhttp.AmzIdentityId] = []byte(identityId)
  100. }
  101. }
  102. // create the folder for bucket, but lazily create actual collection
  103. if err := s3a.mkdir(s3a.option.BucketsPath, bucket, fn); err != nil {
  104. glog.Errorf("PutBucketHandler mkdir: %v", err)
  105. s3err.WriteErrorResponse(w, s3err.ErrInternalError, r)
  106. return
  107. }
  108. writeSuccessResponseEmpty(w)
  109. }
  110. func (s3a *S3ApiServer) DeleteBucketHandler(w http.ResponseWriter, r *http.Request) {
  111. bucket, _ := getBucketAndObject(r)
  112. glog.V(3).Infof("DeleteBucketHandler %s", bucket)
  113. if err := s3a.checkBucket(r, bucket); err != s3err.ErrNone {
  114. s3err.WriteErrorResponse(w, err, r)
  115. return
  116. }
  117. err := s3a.WithFilerClient(func(client filer_pb.SeaweedFilerClient) error {
  118. // delete collection
  119. deleteCollectionRequest := &filer_pb.DeleteCollectionRequest{
  120. Collection: bucket,
  121. }
  122. glog.V(1).Infof("delete collection: %v", deleteCollectionRequest)
  123. if _, err := client.DeleteCollection(context.Background(), deleteCollectionRequest); err != nil {
  124. return fmt.Errorf("delete collection %s: %v", bucket, err)
  125. }
  126. return nil
  127. })
  128. err = s3a.rm(s3a.option.BucketsPath, bucket, false, true)
  129. if err != nil {
  130. s3err.WriteErrorResponse(w, s3err.ErrInternalError, r)
  131. return
  132. }
  133. s3err.WriteEmptyResponse(w, http.StatusNoContent)
  134. }
  135. func (s3a *S3ApiServer) HeadBucketHandler(w http.ResponseWriter, r *http.Request) {
  136. bucket, _ := getBucketAndObject(r)
  137. glog.V(3).Infof("HeadBucketHandler %s", bucket)
  138. if err := s3a.checkBucket(r, bucket); err != s3err.ErrNone {
  139. s3err.WriteErrorResponse(w, err, r)
  140. return
  141. }
  142. writeSuccessResponseEmpty(w)
  143. }
  144. func (s3a *S3ApiServer) checkBucket(r *http.Request, bucket string) s3err.ErrorCode {
  145. entry, err := s3a.getEntry(s3a.option.BucketsPath, bucket)
  146. if entry == nil || err == filer_pb.ErrNotFound {
  147. return s3err.ErrNoSuchBucket
  148. }
  149. if !s3a.hasAccess(r, entry) {
  150. return s3err.ErrAccessDenied
  151. }
  152. return s3err.ErrNone
  153. }
  154. func (s3a *S3ApiServer) hasAccess(r *http.Request, entry *filer_pb.Entry) bool {
  155. isAdmin := r.Header.Get(xhttp.AmzIsAdmin) != ""
  156. if isAdmin {
  157. return true
  158. }
  159. if entry.Extended == nil {
  160. return true
  161. }
  162. identityId := r.Header.Get(xhttp.AmzIdentityId)
  163. if id, ok := entry.Extended[xhttp.AmzIdentityId]; ok {
  164. if identityId != string(id) {
  165. return false
  166. }
  167. }
  168. return true
  169. }
  170. // GetBucketAclHandler Get Bucket ACL
  171. // https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketAcl.html
  172. func (s3a *S3ApiServer) GetBucketAclHandler(w http.ResponseWriter, r *http.Request) {
  173. // collect parameters
  174. bucket, _ := getBucketAndObject(r)
  175. glog.V(3).Infof("GetBucketAclHandler %s", bucket)
  176. if err := s3a.checkBucket(r, bucket); err != s3err.ErrNone {
  177. s3err.WriteErrorResponse(w, err, r)
  178. return
  179. }
  180. response := AccessControlPolicy{}
  181. for _, ident := range s3a.iam.identities {
  182. if len(ident.Credentials) == 0 {
  183. continue
  184. }
  185. for _, action := range ident.Actions {
  186. if !action.overBucket(bucket) || action.getPermission() == "" {
  187. continue
  188. }
  189. id := ident.Credentials[0].AccessKey
  190. if response.Owner.DisplayName == "" && action.isOwner(bucket) && len(ident.Credentials) > 0 {
  191. response.Owner.DisplayName = ident.Name
  192. response.Owner.ID = id
  193. }
  194. response.AccessControlList.Grant = append(response.AccessControlList.Grant, Grant{
  195. Grantee: Grantee{
  196. ID: id,
  197. DisplayName: ident.Name,
  198. Type: "CanonicalUser",
  199. XMLXSI: "CanonicalUser",
  200. XMLNS: "http://www.w3.org/2001/XMLSchema-instance"},
  201. Permission: action.getPermission(),
  202. })
  203. }
  204. }
  205. writeSuccessResponseXML(w, response)
  206. }
  207. // GetBucketLifecycleConfigurationHandler Get Bucket Lifecycle configuration
  208. // https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketLifecycleConfiguration.html
  209. func (s3a *S3ApiServer) GetBucketLifecycleConfigurationHandler(w http.ResponseWriter, r *http.Request) {
  210. // collect parameters
  211. bucket, _ := getBucketAndObject(r)
  212. glog.V(3).Infof("GetBucketAclHandler %s", bucket)
  213. if err := s3a.checkBucket(r, bucket); err != s3err.ErrNone {
  214. s3err.WriteErrorResponse(w, err, r)
  215. return
  216. }
  217. fc, err := filer.ReadFilerConf(s3a.option.Filer, s3a.option.GrpcDialOption, nil)
  218. if err != nil {
  219. glog.Errorf("GetBucketLifecycleConfigurationHandler: %s", err)
  220. s3err.WriteErrorResponse(w, s3err.ErrInternalError, r)
  221. return
  222. }
  223. s3err.WriteErrorResponse(w, s3err.ErrNoSuchLifecycleConfiguration, r)
  224. }
  225. // PutBucketLifecycleConfigurationHandler Put Bucket Lifecycle configuration
  226. // https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketLifecycleConfiguration.html
  227. func (s3a *S3ApiServer) PutBucketLifecycleConfigurationHandler(w http.ResponseWriter, r *http.Request) {
  228. s3err.WriteErrorResponse(w, s3err.ErrNotImplemented, r)
  229. }
  230. // DeleteBucketMetricsConfiguration Delete Bucket Lifecycle
  231. // https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteBucketLifecycle.html
  232. func (s3a *S3ApiServer) DeleteBucketLifecycleHandler(w http.ResponseWriter, r *http.Request) {
  233. s3err.WriteErrorResponse(w, s3err.ErrNotImplemented, r)
  234. }