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.

719 lines
22 KiB

5 months 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
4 years ago
3 years ago
3 years ago
5 months ago
6 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
5 months ago
3 years ago
7 years ago
7 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
5 months 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
3 years ago
3 years ago
3 years ago
3 years ago
5 months ago
  1. package s3api
  2. import (
  3. "bytes"
  4. "context"
  5. "encoding/xml"
  6. "errors"
  7. "fmt"
  8. "github.com/seaweedfs/seaweedfs/weed/s3api/s3acl"
  9. "math"
  10. "net/http"
  11. "strings"
  12. "time"
  13. "github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil"
  14. "github.com/seaweedfs/seaweedfs/weed/s3api/s3bucket"
  15. "github.com/seaweedfs/seaweedfs/weed/filer"
  16. "github.com/seaweedfs/seaweedfs/weed/s3api/s3_constants"
  17. "github.com/seaweedfs/seaweedfs/weed/storage/needle"
  18. "github.com/seaweedfs/seaweedfs/weed/s3api/s3err"
  19. "github.com/aws/aws-sdk-go/aws"
  20. "github.com/aws/aws-sdk-go/service/s3"
  21. "github.com/seaweedfs/seaweedfs/weed/glog"
  22. "github.com/seaweedfs/seaweedfs/weed/pb/filer_pb"
  23. util_http "github.com/seaweedfs/seaweedfs/weed/util/http"
  24. )
  25. func (s3a *S3ApiServer) ListBucketsHandler(w http.ResponseWriter, r *http.Request) {
  26. glog.V(3).Infof("ListBucketsHandler")
  27. var identity *Identity
  28. var s3Err s3err.ErrorCode
  29. if s3a.iam.isEnabled() {
  30. identity, s3Err = s3a.iam.authUser(r)
  31. if s3Err != s3err.ErrNone {
  32. s3err.WriteErrorResponse(w, r, s3Err)
  33. return
  34. }
  35. }
  36. var response ListAllMyBucketsResult
  37. entries, _, err := s3a.list(s3a.option.BucketsPath, "", "", false, math.MaxInt32)
  38. if err != nil {
  39. s3err.WriteErrorResponse(w, r, s3err.ErrInternalError)
  40. return
  41. }
  42. identityId := r.Header.Get(s3_constants.AmzIdentityId)
  43. var listBuckets ListAllMyBucketsList
  44. for _, entry := range entries {
  45. if entry.IsDirectory {
  46. if identity != nil && !identity.canDo(s3_constants.ACTION_LIST, entry.Name, "") {
  47. continue
  48. }
  49. listBuckets.Bucket = append(listBuckets.Bucket, ListAllMyBucketsEntry{
  50. Name: entry.Name,
  51. CreationDate: time.Unix(entry.Attributes.Crtime, 0).UTC(),
  52. })
  53. }
  54. }
  55. response = ListAllMyBucketsResult{
  56. Owner: CanonicalUser{
  57. ID: identityId,
  58. DisplayName: identityId,
  59. },
  60. Buckets: listBuckets,
  61. }
  62. writeSuccessResponseXML(w, r, response)
  63. }
  64. func (s3a *S3ApiServer) PutBucketHandler(w http.ResponseWriter, r *http.Request) {
  65. bucket, _ := s3_constants.GetBucketAndObject(r)
  66. glog.V(3).Infof("PutBucketHandler %s", bucket)
  67. // validate the bucket name
  68. err := s3bucket.VerifyS3BucketName(bucket)
  69. if err != nil {
  70. glog.Errorf("put invalid bucket name: %v %v", bucket, err)
  71. s3err.WriteErrorResponse(w, r, s3err.ErrInvalidBucketName)
  72. return
  73. }
  74. // avoid duplicated buckets
  75. errCode := s3err.ErrNone
  76. if err := s3a.WithFilerClient(false, func(client filer_pb.SeaweedFilerClient) error {
  77. if resp, err := client.CollectionList(context.Background(), &filer_pb.CollectionListRequest{
  78. IncludeEcVolumes: true,
  79. IncludeNormalVolumes: true,
  80. }); err != nil {
  81. glog.Errorf("list collection: %v", err)
  82. return fmt.Errorf("list collections: %v", err)
  83. } else {
  84. for _, c := range resp.Collections {
  85. if s3a.getCollectionName(bucket) == c.Name {
  86. errCode = s3err.ErrBucketAlreadyExists
  87. break
  88. }
  89. }
  90. }
  91. return nil
  92. }); err != nil {
  93. s3err.WriteErrorResponse(w, r, s3err.ErrInternalError)
  94. return
  95. }
  96. if exist, err := s3a.exists(s3a.option.BucketsPath, bucket, true); err == nil && exist {
  97. errCode = s3err.ErrBucketAlreadyExists
  98. }
  99. if errCode != s3err.ErrNone {
  100. s3err.WriteErrorResponse(w, r, errCode)
  101. return
  102. }
  103. objectOwnership := r.Header.Get("X-Amz-Object-Ownership")
  104. requestAccountId := s3acl.GetAccountId(r)
  105. grants, errCode := s3acl.ExtractBucketAcl(r, s3a.iam, objectOwnership, requestAccountId, requestAccountId, true)
  106. if errCode != s3err.ErrNone {
  107. s3err.WriteErrorResponse(w, r, errCode)
  108. return
  109. }
  110. fn := func(entry *filer_pb.Entry) {
  111. if identityId := r.Header.Get(s3_constants.AmzIdentityId); identityId != "" {
  112. if entry.Extended == nil {
  113. entry.Extended = make(map[string][]byte)
  114. }
  115. entry.Extended[s3_constants.AmzIdentityId] = []byte(identityId)
  116. s3a.bucketRegistry.LoadBucketMetadata(entry)
  117. }
  118. if objectOwnership != "" {
  119. if entry.Extended == nil {
  120. entry.Extended = make(map[string][]byte)
  121. }
  122. entry.Extended[s3_constants.ExtOwnershipKey] = []byte(objectOwnership)
  123. }
  124. s3acl.AssembleEntryWithAcp(entry, requestAccountId, grants)
  125. }
  126. // create the folder for bucket, but lazily create actual collection
  127. if err := s3a.mkdir(s3a.option.BucketsPath, bucket, fn); err != nil {
  128. glog.Errorf("PutBucketHandler mkdir: %v", err)
  129. s3err.WriteErrorResponse(w, r, s3err.ErrInternalError)
  130. return
  131. }
  132. // clear cache
  133. s3a.bucketRegistry.ClearCache(bucket)
  134. w.Header().Set("Location", "/"+bucket)
  135. writeSuccessResponseEmpty(w, r)
  136. }
  137. func (s3a *S3ApiServer) DeleteBucketHandler(w http.ResponseWriter, r *http.Request) {
  138. bucket, _ := s3_constants.GetBucketAndObject(r)
  139. glog.V(3).Infof("DeleteBucketHandler %s", bucket)
  140. if err := s3a.checkBucket(r, bucket); err != s3err.ErrNone {
  141. s3err.WriteErrorResponse(w, r, err)
  142. return
  143. }
  144. err := s3a.WithFilerClient(false, func(client filer_pb.SeaweedFilerClient) error {
  145. if !s3a.option.AllowDeleteBucketNotEmpty {
  146. entries, _, err := s3a.list(s3a.option.BucketsPath+"/"+bucket, "", "", false, 2)
  147. if err != nil {
  148. return fmt.Errorf("failed to list bucket %s: %v", bucket, err)
  149. }
  150. for _, entry := range entries {
  151. if entry.Name != s3_constants.MultipartUploadsFolder {
  152. return errors.New(s3err.GetAPIError(s3err.ErrBucketNotEmpty).Code)
  153. }
  154. }
  155. }
  156. // delete collection
  157. deleteCollectionRequest := &filer_pb.DeleteCollectionRequest{
  158. Collection: s3a.getCollectionName(bucket),
  159. }
  160. glog.V(1).Infof("delete collection: %v", deleteCollectionRequest)
  161. if _, err := client.DeleteCollection(context.Background(), deleteCollectionRequest); err != nil {
  162. return fmt.Errorf("delete collection %s: %v", bucket, err)
  163. }
  164. return nil
  165. })
  166. if err != nil {
  167. s3ErrorCode := s3err.ErrInternalError
  168. if err.Error() == s3err.GetAPIError(s3err.ErrBucketNotEmpty).Code {
  169. s3ErrorCode = s3err.ErrBucketNotEmpty
  170. }
  171. s3err.WriteErrorResponse(w, r, s3ErrorCode)
  172. return
  173. }
  174. err = s3a.rm(s3a.option.BucketsPath, bucket, false, true)
  175. if err != nil {
  176. s3err.WriteErrorResponse(w, r, s3err.ErrInternalError)
  177. return
  178. }
  179. // clear cache
  180. s3a.bucketRegistry.ClearCache(bucket)
  181. s3err.WriteEmptyResponse(w, r, http.StatusNoContent)
  182. }
  183. func (s3a *S3ApiServer) HeadBucketHandler(w http.ResponseWriter, r *http.Request) {
  184. bucket, _ := s3_constants.GetBucketAndObject(r)
  185. glog.V(3).Infof("HeadBucketHandler %s", bucket)
  186. _, errorCode := s3a.checkAccessForReadBucket(r, bucket, s3_constants.PermissionRead)
  187. if errorCode != s3err.ErrNone {
  188. s3err.WriteErrorResponse(w, r, errorCode)
  189. return
  190. }
  191. if entry, err := s3a.getEntry(s3a.option.BucketsPath, bucket); entry == nil || err == filer_pb.ErrNotFound {
  192. s3err.WriteErrorResponse(w, r, s3err.ErrNoSuchBucket)
  193. return
  194. }
  195. writeSuccessResponseEmpty(w, r)
  196. }
  197. func (s3a *S3ApiServer) checkBucket(r *http.Request, bucket string) s3err.ErrorCode {
  198. entry, err := s3a.getEntry(s3a.option.BucketsPath, bucket)
  199. if entry == nil || err == filer_pb.ErrNotFound {
  200. return s3err.ErrNoSuchBucket
  201. }
  202. //if iam is enabled, the access was already checked before
  203. if s3a.iam.isEnabled() {
  204. return s3err.ErrNone
  205. }
  206. if !s3a.hasAccess(r, entry) {
  207. return s3err.ErrAccessDenied
  208. }
  209. return s3err.ErrNone
  210. }
  211. func (s3a *S3ApiServer) hasAccess(r *http.Request, entry *filer_pb.Entry) bool {
  212. isAdmin := r.Header.Get(s3_constants.AmzIsAdmin) != ""
  213. if isAdmin {
  214. return true
  215. }
  216. if entry.Extended == nil {
  217. return true
  218. }
  219. identityId := r.Header.Get(s3_constants.AmzIdentityId)
  220. if id, ok := entry.Extended[s3_constants.AmzIdentityId]; ok {
  221. if identityId != string(id) {
  222. glog.V(3).Infof("hasAccess: %s != %s (entry.Extended = %v)", identityId, id, entry.Extended)
  223. return false
  224. }
  225. }
  226. return true
  227. }
  228. // PutBucketAclHandler Put bucket ACL
  229. // https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketAcl.html
  230. func (s3a *S3ApiServer) PutBucketAclHandler(w http.ResponseWriter, r *http.Request) {
  231. bucket, _ := s3_constants.GetBucketAndObject(r)
  232. glog.V(3).Infof("PutBucketAclHandler %s", bucket)
  233. accountId := s3acl.GetAccountId(r)
  234. bucketMetadata, errorCode := s3a.checkAccessForPutBucketAcl(accountId, bucket)
  235. if errorCode != s3err.ErrNone {
  236. s3err.WriteErrorResponse(w, r, errorCode)
  237. return
  238. }
  239. grants, errCode := s3acl.ExtractBucketAcl(r, s3a.iam, bucketMetadata.ObjectOwnership, *bucketMetadata.Owner.ID, accountId, false)
  240. if errCode != s3err.ErrNone {
  241. s3err.WriteErrorResponse(w, r, errCode)
  242. return
  243. }
  244. bucketEntry, err := s3a.getEntry(s3a.option.BucketsPath, bucket)
  245. if err != nil {
  246. glog.Warning(err)
  247. s3err.WriteErrorResponse(w, r, s3err.ErrInternalError)
  248. return
  249. }
  250. errCode = s3acl.AssembleEntryWithAcp(bucketEntry, *bucketMetadata.Owner.ID, grants)
  251. if errCode != s3err.ErrNone {
  252. s3err.WriteErrorResponse(w, r, errCode)
  253. return
  254. }
  255. err = updateBucketEntry(s3a, bucketEntry)
  256. if err != nil {
  257. s3err.WriteErrorResponse(w, r, s3err.ErrInternalError)
  258. return
  259. }
  260. //update local cache
  261. bucketMetadata.Acl = grants
  262. s3err.WriteEmptyResponse(w, r, http.StatusOK)
  263. }
  264. // GetBucketAclHandler Get Bucket ACL
  265. // https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketAcl.html
  266. func (s3a *S3ApiServer) GetBucketAclHandler(w http.ResponseWriter, r *http.Request) {
  267. // collect parameters
  268. bucket, _ := s3_constants.GetBucketAndObject(r)
  269. glog.V(3).Infof("GetBucketAclHandler %s", bucket)
  270. bucketMetadata, errorCode := s3a.checkAccessForReadBucket(r, bucket, s3_constants.PermissionReadAcp)
  271. if s3err.ErrNone != errorCode {
  272. s3err.WriteErrorResponse(w, r, errorCode)
  273. return
  274. }
  275. acp := &s3.PutBucketAclInput{
  276. AccessControlPolicy: &s3.AccessControlPolicy{
  277. Grants: bucketMetadata.Acl,
  278. Owner: bucketMetadata.Owner,
  279. },
  280. }
  281. s3err.WriteAwsXMLResponse(w, r, http.StatusOK, acp)
  282. }
  283. // GetBucketLifecycleConfigurationHandler Get Bucket Lifecycle configuration
  284. // https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketLifecycleConfiguration.html
  285. func (s3a *S3ApiServer) GetBucketLifecycleConfigurationHandler(w http.ResponseWriter, r *http.Request) {
  286. // collect parameters
  287. bucket, _ := s3_constants.GetBucketAndObject(r)
  288. glog.V(3).Infof("GetBucketLifecycleConfigurationHandler %s", bucket)
  289. if err := s3a.checkBucket(r, bucket); err != s3err.ErrNone {
  290. s3err.WriteErrorResponse(w, r, err)
  291. return
  292. }
  293. fc, err := filer.ReadFilerConf(s3a.option.Filer, s3a.option.GrpcDialOption, nil)
  294. if err != nil {
  295. glog.Errorf("GetBucketLifecycleConfigurationHandler: %s", err)
  296. s3err.WriteErrorResponse(w, r, s3err.ErrInternalError)
  297. return
  298. }
  299. ttls := fc.GetCollectionTtls(s3a.getCollectionName(bucket))
  300. if len(ttls) == 0 {
  301. s3err.WriteErrorResponse(w, r, s3err.ErrNoSuchLifecycleConfiguration)
  302. return
  303. }
  304. response := Lifecycle{}
  305. for locationPrefix, internalTtl := range ttls {
  306. ttl, _ := needle.ReadTTL(internalTtl)
  307. days := int(ttl.Minutes() / 60 / 24)
  308. if days == 0 {
  309. continue
  310. }
  311. prefix, found := strings.CutPrefix(locationPrefix, fmt.Sprintf("%s/%s/", s3a.option.BucketsPath, bucket))
  312. if !found {
  313. continue
  314. }
  315. response.Rules = append(response.Rules, Rule{
  316. ID: prefix,
  317. Status: Enabled,
  318. Prefix: Prefix{val: prefix, set: true},
  319. Expiration: Expiration{Days: days, set: true},
  320. })
  321. }
  322. writeSuccessResponseXML(w, r, response)
  323. }
  324. // PutBucketLifecycleConfigurationHandler Put Bucket Lifecycle configuration
  325. // https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketLifecycleConfiguration.html
  326. func (s3a *S3ApiServer) PutBucketLifecycleConfigurationHandler(w http.ResponseWriter, r *http.Request) {
  327. // collect parameters
  328. bucket, _ := s3_constants.GetBucketAndObject(r)
  329. glog.V(3).Infof("PutBucketLifecycleConfigurationHandler %s", bucket)
  330. if err := s3a.checkBucket(r, bucket); err != s3err.ErrNone {
  331. s3err.WriteErrorResponse(w, r, err)
  332. return
  333. }
  334. lifeCycleConfig := Lifecycle{}
  335. if err := xmlDecoder(r.Body, &lifeCycleConfig, r.ContentLength); err != nil {
  336. glog.Warningf("PutBucketLifecycleConfigurationHandler xml decode: %s", err)
  337. s3err.WriteErrorResponse(w, r, s3err.ErrMalformedXML)
  338. return
  339. }
  340. fc, err := filer.ReadFilerConf(s3a.option.Filer, s3a.option.GrpcDialOption, nil)
  341. if err != nil {
  342. glog.Errorf("PutBucketLifecycleConfigurationHandler read filer config: %s", err)
  343. s3err.WriteErrorResponse(w, r, s3err.ErrInternalError)
  344. return
  345. }
  346. collectionName := s3a.getCollectionName(bucket)
  347. collectionTtls := fc.GetCollectionTtls(collectionName)
  348. changed := false
  349. for _, rule := range lifeCycleConfig.Rules {
  350. if rule.Status != Enabled {
  351. continue
  352. }
  353. var rulePrefix string
  354. switch {
  355. case rule.Filter.Prefix.set:
  356. rulePrefix = rule.Filter.Prefix.val
  357. case rule.Prefix.set:
  358. rulePrefix = rule.Prefix.val
  359. case !rule.Expiration.Date.IsZero() || rule.Transition.Days > 0 || !rule.Transition.Date.IsZero():
  360. s3err.WriteErrorResponse(w, r, s3err.ErrNotImplemented)
  361. return
  362. }
  363. if rule.Expiration.Days == 0 {
  364. continue
  365. }
  366. locConf := &filer_pb.FilerConf_PathConf{
  367. LocationPrefix: fmt.Sprintf("%s/%s/%s", s3a.option.BucketsPath, bucket, rulePrefix),
  368. Collection: collectionName,
  369. Ttl: fmt.Sprintf("%dd", rule.Expiration.Days),
  370. }
  371. if ttl, ok := collectionTtls[locConf.LocationPrefix]; ok && ttl == locConf.Ttl {
  372. continue
  373. }
  374. if err := fc.AddLocationConf(locConf); err != nil {
  375. glog.Errorf("PutBucketLifecycleConfigurationHandler add location config: %s", err)
  376. s3err.WriteErrorResponse(w, r, s3err.ErrInternalError)
  377. return
  378. }
  379. changed = true
  380. }
  381. if changed {
  382. var buf bytes.Buffer
  383. if err := fc.ToText(&buf); err != nil {
  384. glog.Errorf("PutBucketLifecycleConfigurationHandler save config to text: %s", err)
  385. s3err.WriteErrorResponse(w, r, s3err.ErrInternalError)
  386. }
  387. if err := s3a.WithFilerClient(false, func(client filer_pb.SeaweedFilerClient) error {
  388. return filer.SaveInsideFiler(client, filer.DirectoryEtcSeaweedFS, filer.FilerConfName, buf.Bytes())
  389. }); err != nil {
  390. glog.Errorf("PutBucketLifecycleConfigurationHandler save config inside filer: %s", err)
  391. s3err.WriteErrorResponse(w, r, s3err.ErrInternalError)
  392. return
  393. }
  394. }
  395. writeSuccessResponseEmpty(w, r)
  396. }
  397. // DeleteBucketLifecycleHandler Delete Bucket Lifecycle
  398. // https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteBucketLifecycle.html
  399. func (s3a *S3ApiServer) DeleteBucketLifecycleHandler(w http.ResponseWriter, r *http.Request) {
  400. // collect parameters
  401. bucket, _ := s3_constants.GetBucketAndObject(r)
  402. glog.V(3).Infof("DeleteBucketLifecycleHandler %s", bucket)
  403. if err := s3a.checkBucket(r, bucket); err != s3err.ErrNone {
  404. s3err.WriteErrorResponse(w, r, err)
  405. return
  406. }
  407. fc, err := filer.ReadFilerConf(s3a.option.Filer, s3a.option.GrpcDialOption, nil)
  408. if err != nil {
  409. glog.Errorf("DeleteBucketLifecycleHandler read filer config: %s", err)
  410. s3err.WriteErrorResponse(w, r, s3err.ErrInternalError)
  411. return
  412. }
  413. collectionTtls := fc.GetCollectionTtls(s3a.getCollectionName(bucket))
  414. changed := false
  415. for prefix, ttl := range collectionTtls {
  416. bucketPrefix := fmt.Sprintf("%s/%s/", s3a.option.BucketsPath, bucket)
  417. if strings.HasPrefix(prefix, bucketPrefix) && strings.HasSuffix(ttl, "d") {
  418. pathConf, found := fc.GetLocationConf(prefix)
  419. if found {
  420. pathConf.Ttl = ""
  421. fc.SetLocationConf(pathConf)
  422. }
  423. changed = true
  424. }
  425. }
  426. if changed {
  427. var buf bytes.Buffer
  428. if err := fc.ToText(&buf); err != nil {
  429. glog.Errorf("DeleteBucketLifecycleHandler save config to text: %s", err)
  430. s3err.WriteErrorResponse(w, r, s3err.ErrInternalError)
  431. }
  432. if err := s3a.WithFilerClient(false, func(client filer_pb.SeaweedFilerClient) error {
  433. return filer.SaveInsideFiler(client, filer.DirectoryEtcSeaweedFS, filer.FilerConfName, buf.Bytes())
  434. }); err != nil {
  435. glog.Errorf("DeleteBucketLifecycleHandler save config inside filer: %s", err)
  436. s3err.WriteErrorResponse(w, r, s3err.ErrInternalError)
  437. return
  438. }
  439. }
  440. s3err.WriteEmptyResponse(w, r, http.StatusNoContent)
  441. }
  442. // GetBucketLocationHandler Get bucket location
  443. // https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketLocation.html
  444. func (s3a *S3ApiServer) GetBucketLocationHandler(w http.ResponseWriter, r *http.Request) {
  445. writeSuccessResponseXML(w, r, CreateBucketConfiguration{})
  446. }
  447. // GetBucketRequestPaymentHandler Get bucket location
  448. // https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketRequestPayment.html
  449. func (s3a *S3ApiServer) GetBucketRequestPaymentHandler(w http.ResponseWriter, r *http.Request) {
  450. writeSuccessResponseXML(w, r, RequestPaymentConfiguration{Payer: "BucketOwner"})
  451. }
  452. // PutBucketOwnershipControls https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketOwnershipControls.html
  453. func (s3a *S3ApiServer) PutBucketOwnershipControls(w http.ResponseWriter, r *http.Request) {
  454. bucket, _ := s3_constants.GetBucketAndObject(r)
  455. glog.V(3).Infof("PutBucketOwnershipControls %s", bucket)
  456. errCode := s3a.checkAccessByOwnership(r, bucket)
  457. if errCode != s3err.ErrNone {
  458. s3err.WriteErrorResponse(w, r, errCode)
  459. return
  460. }
  461. if r.Body == nil || r.Body == http.NoBody {
  462. s3err.WriteErrorResponse(w, r, s3err.ErrInvalidRequest)
  463. return
  464. }
  465. defer util_http.CloseRequest(r)
  466. var v s3.OwnershipControls
  467. err := xmlutil.UnmarshalXML(&v, xml.NewDecoder(r.Body), "")
  468. if err != nil {
  469. s3err.WriteErrorResponse(w, r, s3err.ErrInvalidRequest)
  470. return
  471. }
  472. if len(v.Rules) != 1 {
  473. s3err.WriteErrorResponse(w, r, s3err.ErrInvalidRequest)
  474. return
  475. }
  476. printOwnership := true
  477. newObjectOwnership := *v.Rules[0].ObjectOwnership
  478. switch newObjectOwnership {
  479. case s3_constants.OwnershipObjectWriter:
  480. case s3_constants.OwnershipBucketOwnerPreferred:
  481. case s3_constants.OwnershipBucketOwnerEnforced:
  482. default:
  483. s3err.WriteErrorResponse(w, r, s3err.ErrInvalidRequest)
  484. return
  485. }
  486. bucketEntry, err := s3a.getEntry(s3a.option.BucketsPath, bucket)
  487. if err != nil {
  488. if err == filer_pb.ErrNotFound {
  489. s3err.WriteErrorResponse(w, r, s3err.ErrNoSuchBucket)
  490. return
  491. }
  492. s3err.WriteErrorResponse(w, r, s3err.ErrInternalError)
  493. return
  494. }
  495. oldOwnership, ok := bucketEntry.Extended[s3_constants.ExtOwnershipKey]
  496. if !ok || string(oldOwnership) != newObjectOwnership {
  497. // must reset bucket acl to default(bucket owner with full control permission) before setting ownership
  498. // to `OwnershipBucketOwnerEnforced` (bucket cannot have ACLs set with ObjectOwnership's BucketOwnerEnforced setting)
  499. if newObjectOwnership == s3_constants.OwnershipBucketOwnerEnforced {
  500. acpGrants := s3acl.GetAcpGrants(nil, bucketEntry.Extended)
  501. if len(acpGrants) > 1 {
  502. s3err.WriteErrorResponse(w, r, s3err.InvalidBucketAclWithObjectOwnership)
  503. return
  504. } else if len(acpGrants) == 1 {
  505. bucketOwner := s3acl.GetAcpOwner(bucketEntry.Extended, AccountAdmin.Id)
  506. expectGrant := s3acl.GrantWithFullControl(bucketOwner)
  507. if !s3acl.GrantEquals(acpGrants[0], expectGrant) {
  508. s3err.WriteErrorResponse(w, r, s3err.InvalidBucketAclWithObjectOwnership)
  509. return
  510. }
  511. }
  512. }
  513. if bucketEntry.Extended == nil {
  514. bucketEntry.Extended = make(map[string][]byte)
  515. }
  516. //update local cache
  517. bucketMetadata, eCode := s3a.bucketRegistry.GetBucketMetadata(bucket)
  518. if eCode == s3err.ErrNone {
  519. bucketMetadata.ObjectOwnership = newObjectOwnership
  520. }
  521. bucketEntry.Extended[s3_constants.ExtOwnershipKey] = []byte(newObjectOwnership)
  522. err = s3a.updateEntry(s3a.option.BucketsPath, bucketEntry)
  523. if err != nil {
  524. s3err.WriteErrorResponse(w, r, s3err.ErrInternalError)
  525. return
  526. }
  527. }
  528. if printOwnership {
  529. result := &s3.PutBucketOwnershipControlsInput{
  530. OwnershipControls: &v,
  531. }
  532. s3err.WriteAwsXMLResponse(w, r, http.StatusOK, result)
  533. } else {
  534. writeSuccessResponseEmpty(w, r)
  535. }
  536. }
  537. // GetBucketOwnershipControls https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketOwnershipControls.html
  538. func (s3a *S3ApiServer) GetBucketOwnershipControls(w http.ResponseWriter, r *http.Request) {
  539. bucket, _ := s3_constants.GetBucketAndObject(r)
  540. glog.V(3).Infof("GetBucketOwnershipControls %s", bucket)
  541. errCode := s3a.checkAccessByOwnership(r, bucket)
  542. if errCode != s3err.ErrNone {
  543. s3err.WriteErrorResponse(w, r, errCode)
  544. return
  545. }
  546. bucketEntry, err := s3a.getEntry(s3a.option.BucketsPath, bucket)
  547. if err != nil {
  548. if err == filer_pb.ErrNotFound {
  549. s3err.WriteErrorResponse(w, r, s3err.ErrNoSuchBucket)
  550. return
  551. }
  552. s3err.WriteErrorResponse(w, r, s3err.ErrInternalError)
  553. return
  554. }
  555. v, ok := bucketEntry.Extended[s3_constants.ExtOwnershipKey]
  556. if !ok {
  557. s3err.WriteErrorResponse(w, r, s3err.OwnershipControlsNotFoundError)
  558. return
  559. }
  560. ownership := string(v)
  561. result := &s3.PutBucketOwnershipControlsInput{
  562. OwnershipControls: &s3.OwnershipControls{
  563. Rules: []*s3.OwnershipControlsRule{
  564. {
  565. ObjectOwnership: &ownership,
  566. },
  567. },
  568. },
  569. }
  570. s3err.WriteAwsXMLResponse(w, r, http.StatusOK, result)
  571. }
  572. // DeleteBucketOwnershipControls https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteBucketOwnershipControls.html
  573. func (s3a *S3ApiServer) DeleteBucketOwnershipControls(w http.ResponseWriter, r *http.Request) {
  574. bucket, _ := s3_constants.GetBucketAndObject(r)
  575. glog.V(3).Infof("PutBucketOwnershipControls %s", bucket)
  576. errCode := s3a.checkAccessByOwnership(r, bucket)
  577. if errCode != s3err.ErrNone {
  578. s3err.WriteErrorResponse(w, r, errCode)
  579. return
  580. }
  581. bucketEntry, err := s3a.getEntry(s3a.option.BucketsPath, bucket)
  582. if err != nil {
  583. if err == filer_pb.ErrNotFound {
  584. s3err.WriteErrorResponse(w, r, s3err.ErrNoSuchBucket)
  585. return
  586. }
  587. s3err.WriteErrorResponse(w, r, s3err.ErrInternalError)
  588. return
  589. }
  590. _, ok := bucketEntry.Extended[s3_constants.ExtOwnershipKey]
  591. if !ok {
  592. s3err.WriteErrorResponse(w, r, s3err.OwnershipControlsNotFoundError)
  593. return
  594. }
  595. delete(bucketEntry.Extended, s3_constants.ExtOwnershipKey)
  596. err = s3a.updateEntry(s3a.option.BucketsPath, bucketEntry)
  597. if err != nil {
  598. s3err.WriteErrorResponse(w, r, s3err.ErrInternalError)
  599. return
  600. }
  601. emptyOwnershipControls := &s3.OwnershipControls{
  602. Rules: []*s3.OwnershipControlsRule{},
  603. }
  604. s3err.WriteAwsXMLResponse(w, r, http.StatusOK, emptyOwnershipControls)
  605. }
  606. // GetBucketVersioningHandler Get Bucket Versioning status
  607. // https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketVersioning.html
  608. func (s3a *S3ApiServer) GetBucketVersioningHandler(w http.ResponseWriter, r *http.Request) {
  609. bucket, _ := s3_constants.GetBucketAndObject(r)
  610. glog.V(3).Infof("GetBucketVersioning %s", bucket)
  611. if err := s3a.checkBucket(r, bucket); err != s3err.ErrNone {
  612. s3err.WriteErrorResponse(w, r, err)
  613. return
  614. }
  615. s3err.WriteAwsXMLResponse(w, r, http.StatusOK, &s3.PutBucketVersioningInput{
  616. VersioningConfiguration: &s3.VersioningConfiguration{
  617. Status: aws.String(s3.BucketVersioningStatusSuspended),
  618. },
  619. })
  620. }