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.

584 lines
17 KiB

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
6 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years 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
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. "errors"
  6. "fmt"
  7. "github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil"
  8. "github.com/seaweedfs/seaweedfs/weed/s3api/s3account"
  9. "github.com/seaweedfs/seaweedfs/weed/s3api/s3acl"
  10. "github.com/seaweedfs/seaweedfs/weed/s3api/s3bucket"
  11. "github.com/seaweedfs/seaweedfs/weed/util"
  12. "math"
  13. "net/http"
  14. "time"
  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. )
  24. type ListAllMyBucketsResult struct {
  25. XMLName xml.Name `xml:"http://s3.amazonaws.com/doc/2006-03-01/ ListAllMyBucketsResult"`
  26. Owner *s3.Owner
  27. Buckets []*s3.Bucket `xml:"Buckets>Bucket"`
  28. }
  29. func (s3a *S3ApiServer) ListBucketsHandler(w http.ResponseWriter, r *http.Request) {
  30. glog.V(3).Infof("ListBucketsHandler")
  31. var identity *Identity
  32. var s3Err s3err.ErrorCode
  33. if s3a.iam.isEnabled() {
  34. identity, s3Err = s3a.iam.authUser(r)
  35. if s3Err != s3err.ErrNone {
  36. s3err.WriteErrorResponse(w, r, s3Err)
  37. return
  38. }
  39. }
  40. var response ListAllMyBucketsResult
  41. entries, _, err := s3a.list(s3a.option.BucketsPath, "", "", false, math.MaxInt32)
  42. if err != nil {
  43. s3err.WriteErrorResponse(w, r, s3err.ErrInternalError)
  44. return
  45. }
  46. identityId := r.Header.Get(s3_constants.AmzIdentityId)
  47. var buckets []*s3.Bucket
  48. for _, entry := range entries {
  49. if entry.IsDirectory {
  50. if identity != nil && !identity.canDo(s3_constants.ACTION_LIST, entry.Name, "") {
  51. continue
  52. }
  53. buckets = append(buckets, &s3.Bucket{
  54. Name: aws.String(entry.Name),
  55. CreationDate: aws.Time(time.Unix(entry.Attributes.Crtime, 0).UTC()),
  56. })
  57. }
  58. }
  59. response = ListAllMyBucketsResult{
  60. Owner: &s3.Owner{
  61. ID: aws.String(identityId),
  62. DisplayName: aws.String(identityId),
  63. },
  64. Buckets: buckets,
  65. }
  66. writeSuccessResponseXML(w, r, response)
  67. }
  68. func (s3a *S3ApiServer) PutBucketHandler(w http.ResponseWriter, r *http.Request) {
  69. bucket, _ := s3_constants.GetBucketAndObject(r)
  70. glog.V(3).Infof("PutBucketHandler %s", bucket)
  71. // validate the bucket name
  72. err := s3bucket.VerifyS3BucketName(bucket)
  73. if err != nil {
  74. glog.Errorf("put invalid bucket name: %v %v", bucket, err)
  75. s3err.WriteErrorResponse(w, r, s3err.ErrInvalidBucketName)
  76. return
  77. }
  78. // avoid duplicated buckets
  79. errCode := s3err.ErrNone
  80. if err := s3a.WithFilerClient(false, func(client filer_pb.SeaweedFilerClient) error {
  81. if resp, err := client.CollectionList(context.Background(), &filer_pb.CollectionListRequest{
  82. IncludeEcVolumes: true,
  83. IncludeNormalVolumes: true,
  84. }); err != nil {
  85. glog.Errorf("list collection: %v", err)
  86. return fmt.Errorf("list collections: %v", err)
  87. } else {
  88. for _, c := range resp.Collections {
  89. if bucket == c.Name {
  90. errCode = s3err.ErrBucketAlreadyExists
  91. break
  92. }
  93. }
  94. }
  95. return nil
  96. }); err != nil {
  97. s3err.WriteErrorResponse(w, r, s3err.ErrInternalError)
  98. return
  99. }
  100. if exist, err := s3a.exists(s3a.option.BucketsPath, bucket, true); err == nil && exist {
  101. errCode = s3err.ErrBucketAlreadyExists
  102. }
  103. if errCode != s3err.ErrNone {
  104. s3err.WriteErrorResponse(w, r, errCode)
  105. return
  106. }
  107. if s3a.iam.isEnabled() {
  108. if _, errCode = s3a.iam.authRequest(r, s3_constants.ACTION_ADMIN); errCode != s3err.ErrNone {
  109. s3err.WriteErrorResponse(w, r, errCode)
  110. return
  111. }
  112. }
  113. objectOwnership := r.Header.Get("X-Amz-Object-Ownership")
  114. requestAccountId := s3acl.GetAccountId(r)
  115. grants, errCode := s3acl.ExtractBucketAcl(r, s3a.accountManager, objectOwnership, requestAccountId, requestAccountId, true)
  116. if errCode != s3err.ErrNone {
  117. s3err.WriteErrorResponse(w, r, errCode)
  118. return
  119. }
  120. fn := func(entry *filer_pb.Entry) {
  121. if identityId := r.Header.Get(s3_constants.AmzIdentityId); identityId != "" {
  122. if entry.Extended == nil {
  123. entry.Extended = make(map[string][]byte)
  124. }
  125. entry.Extended[s3_constants.AmzIdentityId] = []byte(identityId)
  126. s3a.bucketRegistry.LoadBucketMetadata(entry)
  127. }
  128. if objectOwnership != "" {
  129. if entry.Extended == nil {
  130. entry.Extended = make(map[string][]byte)
  131. }
  132. entry.Extended[s3_constants.ExtOwnershipKey] = []byte(objectOwnership)
  133. }
  134. s3acl.AssembleEntryWithAcp(entry, requestAccountId, grants)
  135. }
  136. // create the folder for bucket, but lazily create actual collection
  137. if err := s3a.mkdir(s3a.option.BucketsPath, bucket, fn); err != nil {
  138. glog.Errorf("PutBucketHandler mkdir: %v", err)
  139. s3err.WriteErrorResponse(w, r, s3err.ErrInternalError)
  140. return
  141. }
  142. // clear cache
  143. s3a.bucketRegistry.ClearCache(bucket)
  144. w.Header().Set("Location", "/"+bucket)
  145. writeSuccessResponseEmpty(w, r)
  146. }
  147. func (s3a *S3ApiServer) DeleteBucketHandler(w http.ResponseWriter, r *http.Request) {
  148. bucket, _ := s3_constants.GetBucketAndObject(r)
  149. glog.V(3).Infof("DeleteBucketHandler %s", bucket)
  150. if err := s3a.checkBucket(r, bucket); err != s3err.ErrNone {
  151. s3err.WriteErrorResponse(w, r, err)
  152. return
  153. }
  154. err := s3a.WithFilerClient(false, func(client filer_pb.SeaweedFilerClient) error {
  155. if !s3a.option.AllowDeleteBucketNotEmpty {
  156. entries, _, err := s3a.list(s3a.option.BucketsPath+"/"+bucket, "", "", false, 2)
  157. if err != nil {
  158. return fmt.Errorf("failed to list bucket %s: %v", bucket, err)
  159. }
  160. for _, entry := range entries {
  161. if entry.Name != s3_constants.MultipartUploadsFolder {
  162. return errors.New(s3err.GetAPIError(s3err.ErrBucketNotEmpty).Code)
  163. }
  164. }
  165. }
  166. // delete collection
  167. deleteCollectionRequest := &filer_pb.DeleteCollectionRequest{
  168. Collection: bucket,
  169. }
  170. glog.V(1).Infof("delete collection: %v", deleteCollectionRequest)
  171. if _, err := client.DeleteCollection(context.Background(), deleteCollectionRequest); err != nil {
  172. return fmt.Errorf("delete collection %s: %v", bucket, err)
  173. }
  174. return nil
  175. })
  176. if err != nil {
  177. s3ErrorCode := s3err.ErrInternalError
  178. if err.Error() == s3err.GetAPIError(s3err.ErrBucketNotEmpty).Code {
  179. s3ErrorCode = s3err.ErrBucketNotEmpty
  180. }
  181. s3err.WriteErrorResponse(w, r, s3ErrorCode)
  182. return
  183. }
  184. err = s3a.rm(s3a.option.BucketsPath, bucket, false, true)
  185. if err != nil {
  186. s3err.WriteErrorResponse(w, r, s3err.ErrInternalError)
  187. return
  188. }
  189. s3err.WriteEmptyResponse(w, r, http.StatusNoContent)
  190. }
  191. func (s3a *S3ApiServer) HeadBucketHandler(w http.ResponseWriter, r *http.Request) {
  192. bucket, _ := s3_constants.GetBucketAndObject(r)
  193. glog.V(3).Infof("HeadBucketHandler %s", bucket)
  194. _, errorCode := s3a.checkAccessForReadBucket(r, bucket, s3_constants.PermissionRead)
  195. if errorCode != s3err.ErrNone {
  196. s3err.WriteErrorResponse(w, r, errorCode)
  197. return
  198. }
  199. if entry, err := s3a.getEntry(s3a.option.BucketsPath, bucket); entry == nil || err == filer_pb.ErrNotFound {
  200. s3err.WriteErrorResponse(w, r, s3err.ErrNoSuchBucket)
  201. return
  202. }
  203. writeSuccessResponseEmpty(w, r)
  204. }
  205. func (s3a *S3ApiServer) checkBucket(r *http.Request, bucket string) s3err.ErrorCode {
  206. entry, err := s3a.getEntry(s3a.option.BucketsPath, bucket)
  207. if entry == nil || err == filer_pb.ErrNotFound {
  208. return s3err.ErrNoSuchBucket
  209. }
  210. if !s3a.hasAccess(r, entry) {
  211. return s3err.ErrAccessDenied
  212. }
  213. return s3err.ErrNone
  214. }
  215. func (s3a *S3ApiServer) hasAccess(r *http.Request, entry *filer_pb.Entry) bool {
  216. isAdmin := r.Header.Get(s3_constants.AmzIsAdmin) != ""
  217. if isAdmin {
  218. return true
  219. }
  220. if entry.Extended == nil {
  221. return true
  222. }
  223. identityId := r.Header.Get(s3_constants.AmzIdentityId)
  224. if id, ok := entry.Extended[s3_constants.AmzIdentityId]; ok {
  225. if identityId != string(id) {
  226. return false
  227. }
  228. }
  229. return true
  230. }
  231. // PutBucketAclHandler Put bucket ACL
  232. // https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketAcl.html
  233. func (s3a *S3ApiServer) PutBucketAclHandler(w http.ResponseWriter, r *http.Request) {
  234. bucket, _ := s3_constants.GetBucketAndObject(r)
  235. glog.V(3).Infof("PutBucketAclHandler %s", bucket)
  236. accountId := s3acl.GetAccountId(r)
  237. bucketMetadata, errorCode := s3a.checkAccessForPutBucketAcl(accountId, bucket)
  238. if errorCode != s3err.ErrNone {
  239. s3err.WriteErrorResponse(w, r, errorCode)
  240. return
  241. }
  242. grants, errCode := s3acl.ExtractBucketAcl(r, s3a.accountManager, bucketMetadata.ObjectOwnership, *bucketMetadata.Owner.ID, accountId, false)
  243. if errCode != s3err.ErrNone {
  244. s3err.WriteErrorResponse(w, r, errCode)
  245. return
  246. }
  247. bucketEntry, err := s3a.getEntry(s3a.option.BucketsPath, bucket)
  248. if err != nil {
  249. glog.Warning(err)
  250. s3err.WriteErrorResponse(w, r, s3err.ErrInternalError)
  251. return
  252. }
  253. errCode = s3acl.AssembleEntryWithAcp(bucketEntry, *bucketMetadata.Owner.ID, grants)
  254. if errCode != s3err.ErrNone {
  255. s3err.WriteErrorResponse(w, r, errCode)
  256. return
  257. }
  258. err = updateBucketEntry(s3a, bucketEntry)
  259. if err != nil {
  260. s3err.WriteErrorResponse(w, r, s3err.ErrInternalError)
  261. return
  262. }
  263. //update local cache
  264. bucketMetadata.Acl = grants
  265. s3err.WriteEmptyResponse(w, r, http.StatusOK)
  266. }
  267. // GetBucketAclHandler Get Bucket ACL
  268. // https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketAcl.html
  269. func (s3a *S3ApiServer) GetBucketAclHandler(w http.ResponseWriter, r *http.Request) {
  270. // collect parameters
  271. bucket, _ := s3_constants.GetBucketAndObject(r)
  272. glog.V(3).Infof("GetBucketAclHandler %s", bucket)
  273. bucketMetadata, errorCode := s3a.checkAccessForReadBucket(r, bucket, s3_constants.PermissionReadAcp)
  274. if s3err.ErrNone != errorCode {
  275. s3err.WriteErrorResponse(w, r, errorCode)
  276. return
  277. }
  278. acp := &s3.PutBucketAclInput{
  279. AccessControlPolicy: &s3.AccessControlPolicy{
  280. Grants: bucketMetadata.Acl,
  281. Owner: bucketMetadata.Owner,
  282. },
  283. }
  284. s3err.WriteAwsXMLResponse(w, r, http.StatusOK, acp)
  285. }
  286. // GetBucketLifecycleConfigurationHandler Get Bucket Lifecycle configuration
  287. // https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketLifecycleConfiguration.html
  288. func (s3a *S3ApiServer) GetBucketLifecycleConfigurationHandler(w http.ResponseWriter, r *http.Request) {
  289. // collect parameters
  290. bucket, _ := s3_constants.GetBucketAndObject(r)
  291. glog.V(3).Infof("GetBucketLifecycleConfigurationHandler %s", bucket)
  292. if err := s3a.checkBucket(r, bucket); err != s3err.ErrNone {
  293. s3err.WriteErrorResponse(w, r, err)
  294. return
  295. }
  296. fc, err := filer.ReadFilerConf(s3a.option.Filer, s3a.option.GrpcDialOption, nil)
  297. if err != nil {
  298. glog.Errorf("GetBucketLifecycleConfigurationHandler: %s", err)
  299. s3err.WriteErrorResponse(w, r, s3err.ErrInternalError)
  300. return
  301. }
  302. ttls := fc.GetCollectionTtls(bucket)
  303. if len(ttls) == 0 {
  304. s3err.WriteErrorResponse(w, r, s3err.ErrNoSuchLifecycleConfiguration)
  305. return
  306. }
  307. response := Lifecycle{}
  308. for prefix, internalTtl := range ttls {
  309. ttl, _ := needle.ReadTTL(internalTtl)
  310. days := int(ttl.Minutes() / 60 / 24)
  311. if days == 0 {
  312. continue
  313. }
  314. response.Rules = append(response.Rules, Rule{
  315. Status: Enabled, Filter: Filter{
  316. Prefix: Prefix{string: prefix, set: true},
  317. set: true,
  318. },
  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. s3err.WriteErrorResponse(w, r, s3err.ErrNotImplemented)
  328. }
  329. // DeleteBucketMetricsConfiguration Delete Bucket Lifecycle
  330. // https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteBucketLifecycle.html
  331. func (s3a *S3ApiServer) DeleteBucketLifecycleHandler(w http.ResponseWriter, r *http.Request) {
  332. s3err.WriteEmptyResponse(w, r, http.StatusNoContent)
  333. }
  334. // GetBucketLocationHandler Get bucket location
  335. // https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketLocation.html
  336. func (s3a *S3ApiServer) GetBucketLocationHandler(w http.ResponseWriter, r *http.Request) {
  337. writeSuccessResponseXML(w, r, LocationConstraint{})
  338. }
  339. // GetBucketRequestPaymentHandler Get bucket location
  340. // https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketRequestPayment.html
  341. func (s3a *S3ApiServer) GetBucketRequestPaymentHandler(w http.ResponseWriter, r *http.Request) {
  342. writeSuccessResponseXML(w, r, RequestPaymentConfiguration{Payer: "BucketOwner"})
  343. }
  344. // PutBucketOwnershipControls https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketOwnershipControls.html
  345. func (s3a *S3ApiServer) PutBucketOwnershipControls(w http.ResponseWriter, r *http.Request) {
  346. bucket, _ := s3_constants.GetBucketAndObject(r)
  347. glog.V(3).Infof("PutBucketOwnershipControls %s", bucket)
  348. errCode := s3a.checkAccessByOwnership(r, bucket)
  349. if errCode != s3err.ErrNone {
  350. s3err.WriteErrorResponse(w, r, errCode)
  351. return
  352. }
  353. if r.Body == nil || r.Body == http.NoBody {
  354. s3err.WriteErrorResponse(w, r, s3err.ErrInvalidRequest)
  355. return
  356. }
  357. defer util.CloseRequest(r)
  358. var v s3.OwnershipControls
  359. err := xmlutil.UnmarshalXML(&v, xml.NewDecoder(r.Body), "")
  360. if err != nil {
  361. s3err.WriteErrorResponse(w, r, s3err.ErrInvalidRequest)
  362. return
  363. }
  364. if len(v.Rules) != 1 {
  365. s3err.WriteErrorResponse(w, r, s3err.ErrInvalidRequest)
  366. return
  367. }
  368. printOwnership := true
  369. newObjectOwnership := *v.Rules[0].ObjectOwnership
  370. switch newObjectOwnership {
  371. case s3_constants.OwnershipObjectWriter:
  372. case s3_constants.OwnershipBucketOwnerPreferred:
  373. case s3_constants.OwnershipBucketOwnerEnforced:
  374. default:
  375. s3err.WriteErrorResponse(w, r, s3err.ErrInvalidRequest)
  376. return
  377. }
  378. bucketEntry, err := s3a.getEntry(s3a.option.BucketsPath, bucket)
  379. if err != nil {
  380. if err == filer_pb.ErrNotFound {
  381. s3err.WriteErrorResponse(w, r, s3err.ErrNoSuchBucket)
  382. return
  383. }
  384. s3err.WriteErrorResponse(w, r, s3err.ErrInternalError)
  385. return
  386. }
  387. oldOwnership, ok := bucketEntry.Extended[s3_constants.ExtOwnershipKey]
  388. if !ok || string(oldOwnership) != newObjectOwnership {
  389. // must reset bucket acl to default(bucket owner with full control permission) before setting ownership
  390. // to `OwnershipBucketOwnerEnforced` (bucket cannot have ACLs set with ObjectOwnership's BucketOwnerEnforced setting)
  391. if newObjectOwnership == s3_constants.OwnershipBucketOwnerEnforced {
  392. acpGrants := s3acl.GetAcpGrants(nil, bucketEntry.Extended)
  393. if len(acpGrants) > 1 {
  394. s3err.WriteErrorResponse(w, r, s3err.InvalidBucketAclWithObjectOwnership)
  395. return
  396. } else if len(acpGrants) == 1 {
  397. bucketOwner := s3acl.GetAcpOwner(bucketEntry.Extended, s3account.AccountAdmin.Id)
  398. expectGrant := s3acl.GrantWithFullControl(bucketOwner)
  399. if !s3acl.GrantEquals(acpGrants[0], expectGrant) {
  400. s3err.WriteErrorResponse(w, r, s3err.InvalidBucketAclWithObjectOwnership)
  401. return
  402. }
  403. }
  404. }
  405. if bucketEntry.Extended == nil {
  406. bucketEntry.Extended = make(map[string][]byte)
  407. }
  408. //update local cache
  409. bucketMetadata, eCode := s3a.bucketRegistry.GetBucketMetadata(bucket)
  410. if eCode == s3err.ErrNone {
  411. bucketMetadata.ObjectOwnership = newObjectOwnership
  412. }
  413. bucketEntry.Extended[s3_constants.ExtOwnershipKey] = []byte(newObjectOwnership)
  414. err = s3a.updateEntry(s3a.option.BucketsPath, bucketEntry)
  415. if err != nil {
  416. s3err.WriteErrorResponse(w, r, s3err.ErrInternalError)
  417. return
  418. }
  419. }
  420. if printOwnership {
  421. result := &s3.PutBucketOwnershipControlsInput{
  422. OwnershipControls: &v,
  423. }
  424. s3err.WriteAwsXMLResponse(w, r, http.StatusOK, result)
  425. } else {
  426. writeSuccessResponseEmpty(w, r)
  427. }
  428. }
  429. // GetBucketOwnershipControls https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketOwnershipControls.html
  430. func (s3a *S3ApiServer) GetBucketOwnershipControls(w http.ResponseWriter, r *http.Request) {
  431. bucket, _ := s3_constants.GetBucketAndObject(r)
  432. glog.V(3).Infof("GetBucketOwnershipControls %s", bucket)
  433. errCode := s3a.checkAccessByOwnership(r, bucket)
  434. if errCode != s3err.ErrNone {
  435. s3err.WriteErrorResponse(w, r, errCode)
  436. return
  437. }
  438. bucketEntry, err := s3a.getEntry(s3a.option.BucketsPath, bucket)
  439. if err != nil {
  440. if err == filer_pb.ErrNotFound {
  441. s3err.WriteErrorResponse(w, r, s3err.ErrNoSuchBucket)
  442. return
  443. }
  444. s3err.WriteErrorResponse(w, r, s3err.ErrInternalError)
  445. return
  446. }
  447. v, ok := bucketEntry.Extended[s3_constants.ExtOwnershipKey]
  448. if !ok {
  449. s3err.WriteErrorResponse(w, r, s3err.OwnershipControlsNotFoundError)
  450. return
  451. }
  452. ownership := string(v)
  453. result := &s3.PutBucketOwnershipControlsInput{
  454. OwnershipControls: &s3.OwnershipControls{
  455. Rules: []*s3.OwnershipControlsRule{
  456. {
  457. ObjectOwnership: &ownership,
  458. },
  459. },
  460. },
  461. }
  462. s3err.WriteAwsXMLResponse(w, r, http.StatusOK, result)
  463. }
  464. // DeleteBucketOwnershipControls https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteBucketOwnershipControls.html
  465. func (s3a *S3ApiServer) DeleteBucketOwnershipControls(w http.ResponseWriter, r *http.Request) {
  466. bucket, _ := s3_constants.GetBucketAndObject(r)
  467. glog.V(3).Infof("PutBucketOwnershipControls %s", bucket)
  468. errCode := s3a.checkAccessByOwnership(r, bucket)
  469. if errCode != s3err.ErrNone {
  470. s3err.WriteErrorResponse(w, r, errCode)
  471. return
  472. }
  473. bucketEntry, err := s3a.getEntry(s3a.option.BucketsPath, bucket)
  474. if err != nil {
  475. if err == filer_pb.ErrNotFound {
  476. s3err.WriteErrorResponse(w, r, s3err.ErrNoSuchBucket)
  477. return
  478. }
  479. s3err.WriteErrorResponse(w, r, s3err.ErrInternalError)
  480. return
  481. }
  482. _, ok := bucketEntry.Extended[s3_constants.ExtOwnershipKey]
  483. if !ok {
  484. s3err.WriteErrorResponse(w, r, s3err.OwnershipControlsNotFoundError)
  485. return
  486. }
  487. delete(bucketEntry.Extended, s3_constants.ExtOwnershipKey)
  488. err = s3a.updateEntry(s3a.option.BucketsPath, bucketEntry)
  489. if err != nil {
  490. s3err.WriteErrorResponse(w, r, s3err.ErrInternalError)
  491. return
  492. }
  493. emptyOwnershipControls := &s3.OwnershipControls{
  494. Rules: []*s3.OwnershipControlsRule{},
  495. }
  496. s3err.WriteAwsXMLResponse(w, r, http.StatusOK, emptyOwnershipControls)
  497. }