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.

310 lines
8.6 KiB

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