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.

490 lines
14 KiB

7 years ago
7 years ago
3 years ago
7 years ago
3 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
3 years ago
4 years ago
3 years ago
3 years ago
7 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
  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/util"
  9. "math"
  10. "net/http"
  11. "time"
  12. "github.com/seaweedfs/seaweedfs/weed/filer"
  13. "github.com/seaweedfs/seaweedfs/weed/s3api/s3_constants"
  14. "github.com/seaweedfs/seaweedfs/weed/storage/needle"
  15. "github.com/seaweedfs/seaweedfs/weed/s3api/s3err"
  16. "github.com/aws/aws-sdk-go/aws"
  17. "github.com/aws/aws-sdk-go/service/s3"
  18. "github.com/seaweedfs/seaweedfs/weed/glog"
  19. "github.com/seaweedfs/seaweedfs/weed/pb/filer_pb"
  20. )
  21. type ListAllMyBucketsResult struct {
  22. XMLName xml.Name `xml:"http://s3.amazonaws.com/doc/2006-03-01/ ListAllMyBucketsResult"`
  23. Owner *s3.Owner
  24. Buckets []*s3.Bucket `xml:"Buckets>Bucket"`
  25. }
  26. func (s3a *S3ApiServer) ListBucketsHandler(w http.ResponseWriter, r *http.Request) {
  27. glog.V(3).Infof("ListBucketsHandler")
  28. var identity *Identity
  29. var s3Err s3err.ErrorCode
  30. if s3a.iam.isEnabled() {
  31. identity, s3Err = s3a.iam.authUser(r)
  32. if s3Err != s3err.ErrNone {
  33. s3err.WriteErrorResponse(w, r, s3Err)
  34. return
  35. }
  36. }
  37. var response ListAllMyBucketsResult
  38. entries, _, err := s3a.list(s3a.option.BucketsPath, "", "", false, math.MaxInt32)
  39. if err != nil {
  40. s3err.WriteErrorResponse(w, r, s3err.ErrInternalError)
  41. return
  42. }
  43. identityId := r.Header.Get(s3_constants.AmzIdentityId)
  44. var buckets []*s3.Bucket
  45. for _, entry := range entries {
  46. if entry.IsDirectory {
  47. if identity != nil && !identity.canDo(s3_constants.ACTION_LIST, entry.Name, "") {
  48. continue
  49. }
  50. buckets = append(buckets, &s3.Bucket{
  51. Name: aws.String(entry.Name),
  52. CreationDate: aws.Time(time.Unix(entry.Attributes.Crtime, 0).UTC()),
  53. })
  54. }
  55. }
  56. response = ListAllMyBucketsResult{
  57. Owner: &s3.Owner{
  58. ID: aws.String(identityId),
  59. DisplayName: aws.String(identityId),
  60. },
  61. Buckets: buckets,
  62. }
  63. writeSuccessResponseXML(w, r, response)
  64. }
  65. func (s3a *S3ApiServer) PutBucketHandler(w http.ResponseWriter, r *http.Request) {
  66. bucket, _ := s3_constants.GetBucketAndObject(r)
  67. glog.V(3).Infof("PutBucketHandler %s", bucket)
  68. // avoid duplicated buckets
  69. errCode := s3err.ErrNone
  70. if err := s3a.WithFilerClient(false, func(client filer_pb.SeaweedFilerClient) error {
  71. if resp, err := client.CollectionList(context.Background(), &filer_pb.CollectionListRequest{
  72. IncludeEcVolumes: true,
  73. IncludeNormalVolumes: true,
  74. }); err != nil {
  75. glog.Errorf("list collection: %v", err)
  76. return fmt.Errorf("list collections: %v", err)
  77. } else {
  78. for _, c := range resp.Collections {
  79. if bucket == c.Name {
  80. errCode = s3err.ErrBucketAlreadyExists
  81. break
  82. }
  83. }
  84. }
  85. return nil
  86. }); err != nil {
  87. s3err.WriteErrorResponse(w, r, s3err.ErrInternalError)
  88. return
  89. }
  90. if exist, err := s3a.exists(s3a.option.BucketsPath, bucket, true); err == nil && exist {
  91. errCode = s3err.ErrBucketAlreadyExists
  92. }
  93. if errCode != s3err.ErrNone {
  94. s3err.WriteErrorResponse(w, r, errCode)
  95. return
  96. }
  97. if s3a.iam.isEnabled() {
  98. if _, errCode = s3a.iam.authRequest(r, s3_constants.ACTION_ADMIN); errCode != s3err.ErrNone {
  99. s3err.WriteErrorResponse(w, r, errCode)
  100. return
  101. }
  102. }
  103. fn := func(entry *filer_pb.Entry) {
  104. if identityId := r.Header.Get(s3_constants.AmzIdentityId); identityId != "" {
  105. if entry.Extended == nil {
  106. entry.Extended = make(map[string][]byte)
  107. }
  108. entry.Extended[s3_constants.AmzIdentityId] = []byte(identityId)
  109. }
  110. }
  111. // create the folder for bucket, but lazily create actual collection
  112. if err := s3a.mkdir(s3a.option.BucketsPath, bucket, fn); err != nil {
  113. glog.Errorf("PutBucketHandler mkdir: %v", err)
  114. s3err.WriteErrorResponse(w, r, s3err.ErrInternalError)
  115. return
  116. }
  117. w.Header().Set("Location", "/"+bucket)
  118. writeSuccessResponseEmpty(w, r)
  119. }
  120. func (s3a *S3ApiServer) DeleteBucketHandler(w http.ResponseWriter, r *http.Request) {
  121. bucket, _ := s3_constants.GetBucketAndObject(r)
  122. glog.V(3).Infof("DeleteBucketHandler %s", bucket)
  123. if err := s3a.checkBucket(r, bucket); err != s3err.ErrNone {
  124. s3err.WriteErrorResponse(w, r, err)
  125. return
  126. }
  127. err := s3a.WithFilerClient(false, func(client filer_pb.SeaweedFilerClient) error {
  128. if !s3a.option.AllowDeleteBucketNotEmpty {
  129. entries, _, err := s3a.list(s3a.option.BucketsPath+"/"+bucket, "", "", false, 2)
  130. if err != nil {
  131. return fmt.Errorf("failed to list bucket %s: %v", bucket, err)
  132. }
  133. for _, entry := range entries {
  134. if entry.Name != s3_constants.MultipartUploadsFolder {
  135. return errors.New(s3err.GetAPIError(s3err.ErrBucketNotEmpty).Code)
  136. }
  137. }
  138. }
  139. // delete collection
  140. deleteCollectionRequest := &filer_pb.DeleteCollectionRequest{
  141. Collection: bucket,
  142. }
  143. glog.V(1).Infof("delete collection: %v", deleteCollectionRequest)
  144. if _, err := client.DeleteCollection(context.Background(), deleteCollectionRequest); err != nil {
  145. return fmt.Errorf("delete collection %s: %v", bucket, err)
  146. }
  147. return nil
  148. })
  149. if err != nil {
  150. s3ErrorCode := s3err.ErrInternalError
  151. if err.Error() == s3err.GetAPIError(s3err.ErrBucketNotEmpty).Code {
  152. s3ErrorCode = s3err.ErrBucketNotEmpty
  153. }
  154. s3err.WriteErrorResponse(w, r, s3ErrorCode)
  155. return
  156. }
  157. err = s3a.rm(s3a.option.BucketsPath, bucket, false, true)
  158. if err != nil {
  159. s3err.WriteErrorResponse(w, r, s3err.ErrInternalError)
  160. return
  161. }
  162. s3err.WriteEmptyResponse(w, r, http.StatusNoContent)
  163. }
  164. func (s3a *S3ApiServer) HeadBucketHandler(w http.ResponseWriter, r *http.Request) {
  165. bucket, _ := s3_constants.GetBucketAndObject(r)
  166. glog.V(3).Infof("HeadBucketHandler %s", bucket)
  167. _, errorCode := s3a.checkAccessForReadBucket(r, bucket, s3_constants.PermissionRead)
  168. if errorCode != s3err.ErrNone {
  169. s3err.WriteErrorResponse(w, r, errorCode)
  170. return
  171. }
  172. if entry, err := s3a.getEntry(s3a.option.BucketsPath, bucket); entry == nil || err == filer_pb.ErrNotFound {
  173. s3err.WriteErrorResponse(w, r, s3err.ErrNoSuchBucket)
  174. return
  175. }
  176. writeSuccessResponseEmpty(w, r)
  177. }
  178. func (s3a *S3ApiServer) checkBucket(r *http.Request, bucket string) s3err.ErrorCode {
  179. entry, err := s3a.getEntry(s3a.option.BucketsPath, bucket)
  180. if entry == nil || err == filer_pb.ErrNotFound {
  181. return s3err.ErrNoSuchBucket
  182. }
  183. if !s3a.hasAccess(r, entry) {
  184. return s3err.ErrAccessDenied
  185. }
  186. return s3err.ErrNone
  187. }
  188. func (s3a *S3ApiServer) hasAccess(r *http.Request, entry *filer_pb.Entry) bool {
  189. isAdmin := r.Header.Get(s3_constants.AmzIsAdmin) != ""
  190. if isAdmin {
  191. return true
  192. }
  193. if entry.Extended == nil {
  194. return true
  195. }
  196. identityId := r.Header.Get(s3_constants.AmzIdentityId)
  197. if id, ok := entry.Extended[s3_constants.AmzIdentityId]; ok {
  198. if identityId != string(id) {
  199. return false
  200. }
  201. }
  202. return true
  203. }
  204. // GetBucketAclHandler Get Bucket ACL
  205. // https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketAcl.html
  206. func (s3a *S3ApiServer) GetBucketAclHandler(w http.ResponseWriter, r *http.Request) {
  207. // collect parameters
  208. bucket, _ := s3_constants.GetBucketAndObject(r)
  209. glog.V(3).Infof("GetBucketAclHandler %s", bucket)
  210. bucketMetadata, errorCode := s3a.checkAccessForReadBucket(r, bucket, s3_constants.PermissionReadAcp)
  211. if s3err.ErrNone != errorCode {
  212. s3err.WriteErrorResponse(w, r, errorCode)
  213. return
  214. }
  215. acp := &s3.PutBucketAclInput{
  216. AccessControlPolicy: &s3.AccessControlPolicy{
  217. Grants: bucketMetadata.Acl,
  218. Owner: bucketMetadata.Owner,
  219. },
  220. }
  221. s3err.WriteAwsXMLResponse(w, r, http.StatusOK, acp)
  222. }
  223. // GetBucketLifecycleConfigurationHandler Get Bucket Lifecycle configuration
  224. // https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketLifecycleConfiguration.html
  225. func (s3a *S3ApiServer) GetBucketLifecycleConfigurationHandler(w http.ResponseWriter, r *http.Request) {
  226. // collect parameters
  227. bucket, _ := s3_constants.GetBucketAndObject(r)
  228. glog.V(3).Infof("GetBucketLifecycleConfigurationHandler %s", bucket)
  229. if err := s3a.checkBucket(r, bucket); err != s3err.ErrNone {
  230. s3err.WriteErrorResponse(w, r, err)
  231. return
  232. }
  233. fc, err := filer.ReadFilerConf(s3a.option.Filer, s3a.option.GrpcDialOption, nil)
  234. if err != nil {
  235. glog.Errorf("GetBucketLifecycleConfigurationHandler: %s", err)
  236. s3err.WriteErrorResponse(w, r, s3err.ErrInternalError)
  237. return
  238. }
  239. ttls := fc.GetCollectionTtls(bucket)
  240. if len(ttls) == 0 {
  241. s3err.WriteErrorResponse(w, r, s3err.ErrNoSuchLifecycleConfiguration)
  242. return
  243. }
  244. response := Lifecycle{}
  245. for prefix, internalTtl := range ttls {
  246. ttl, _ := needle.ReadTTL(internalTtl)
  247. days := int(ttl.Minutes() / 60 / 24)
  248. if days == 0 {
  249. continue
  250. }
  251. response.Rules = append(response.Rules, Rule{
  252. Status: Enabled, Filter: Filter{
  253. Prefix: Prefix{string: prefix, set: true},
  254. set: true,
  255. },
  256. Expiration: Expiration{Days: days, set: true},
  257. })
  258. }
  259. writeSuccessResponseXML(w, r, response)
  260. }
  261. // PutBucketLifecycleConfigurationHandler Put Bucket Lifecycle configuration
  262. // https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketLifecycleConfiguration.html
  263. func (s3a *S3ApiServer) PutBucketLifecycleConfigurationHandler(w http.ResponseWriter, r *http.Request) {
  264. s3err.WriteErrorResponse(w, r, s3err.ErrNotImplemented)
  265. }
  266. // DeleteBucketMetricsConfiguration Delete Bucket Lifecycle
  267. // https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteBucketLifecycle.html
  268. func (s3a *S3ApiServer) DeleteBucketLifecycleHandler(w http.ResponseWriter, r *http.Request) {
  269. s3err.WriteEmptyResponse(w, r, http.StatusNoContent)
  270. }
  271. // GetBucketLocationHandler Get bucket location
  272. // https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketLocation.html
  273. func (s3a *S3ApiServer) GetBucketLocationHandler(w http.ResponseWriter, r *http.Request) {
  274. writeSuccessResponseXML(w, r, LocationConstraint{})
  275. }
  276. // GetBucketRequestPaymentHandler Get bucket location
  277. // https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketRequestPayment.html
  278. func (s3a *S3ApiServer) GetBucketRequestPaymentHandler(w http.ResponseWriter, r *http.Request) {
  279. writeSuccessResponseXML(w, r, RequestPaymentConfiguration{Payer: "BucketOwner"})
  280. }
  281. // PutBucketOwnershipControls https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketOwnershipControls.html
  282. func (s3a *S3ApiServer) PutBucketOwnershipControls(w http.ResponseWriter, r *http.Request) {
  283. bucket, _ := s3_constants.GetBucketAndObject(r)
  284. glog.V(3).Infof("PutBucketOwnershipControls %s", bucket)
  285. errCode := s3a.checkAccessByOwnership(r, bucket)
  286. if errCode != s3err.ErrNone {
  287. s3err.WriteErrorResponse(w, r, errCode)
  288. return
  289. }
  290. if r.Body == nil || r.Body == http.NoBody {
  291. s3err.WriteErrorResponse(w, r, s3err.ErrInvalidRequest)
  292. return
  293. }
  294. var v s3.OwnershipControls
  295. defer util.CloseRequest(r)
  296. err := xmlutil.UnmarshalXML(&v, xml.NewDecoder(r.Body), "")
  297. if err != nil {
  298. s3err.WriteErrorResponse(w, r, s3err.ErrInvalidRequest)
  299. return
  300. }
  301. if len(v.Rules) != 1 {
  302. s3err.WriteErrorResponse(w, r, s3err.ErrInvalidRequest)
  303. return
  304. }
  305. printOwnership := true
  306. ownership := *v.Rules[0].ObjectOwnership
  307. switch ownership {
  308. case s3_constants.OwnershipObjectWriter:
  309. case s3_constants.OwnershipBucketOwnerPreferred:
  310. case s3_constants.OwnershipBucketOwnerEnforced:
  311. printOwnership = false
  312. default:
  313. s3err.WriteErrorResponse(w, r, s3err.ErrInvalidRequest)
  314. return
  315. }
  316. bucketEntry, err := s3a.getEntry(s3a.option.BucketsPath, bucket)
  317. if err != nil {
  318. if err == filer_pb.ErrNotFound {
  319. s3err.WriteErrorResponse(w, r, s3err.ErrNoSuchBucket)
  320. return
  321. }
  322. s3err.WriteErrorResponse(w, r, s3err.ErrInternalError)
  323. return
  324. }
  325. oldOwnership, ok := bucketEntry.Extended[s3_constants.ExtOwnershipKey]
  326. if !ok || string(oldOwnership) != ownership {
  327. if bucketEntry.Extended == nil {
  328. bucketEntry.Extended = make(map[string][]byte)
  329. }
  330. bucketEntry.Extended[s3_constants.ExtOwnershipKey] = []byte(ownership)
  331. err = s3a.updateEntry(s3a.option.BucketsPath, bucketEntry)
  332. if err != nil {
  333. s3err.WriteErrorResponse(w, r, s3err.ErrInternalError)
  334. return
  335. }
  336. }
  337. if printOwnership {
  338. result := &s3.PutBucketOwnershipControlsInput{
  339. OwnershipControls: &v,
  340. }
  341. s3err.WriteAwsXMLResponse(w, r, http.StatusOK, result)
  342. } else {
  343. writeSuccessResponseEmpty(w, r)
  344. }
  345. }
  346. // GetBucketOwnershipControls https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketOwnershipControls.html
  347. func (s3a *S3ApiServer) GetBucketOwnershipControls(w http.ResponseWriter, r *http.Request) {
  348. bucket, _ := s3_constants.GetBucketAndObject(r)
  349. glog.V(3).Infof("GetBucketOwnershipControls %s", bucket)
  350. errCode := s3a.checkAccessByOwnership(r, bucket)
  351. if errCode != s3err.ErrNone {
  352. s3err.WriteErrorResponse(w, r, errCode)
  353. return
  354. }
  355. bucketEntry, err := s3a.getEntry(s3a.option.BucketsPath, bucket)
  356. if err != nil {
  357. if err == filer_pb.ErrNotFound {
  358. s3err.WriteErrorResponse(w, r, s3err.ErrNoSuchBucket)
  359. return
  360. }
  361. s3err.WriteErrorResponse(w, r, s3err.ErrInternalError)
  362. return
  363. }
  364. v, ok := bucketEntry.Extended[s3_constants.ExtOwnershipKey]
  365. if !ok {
  366. s3err.WriteErrorResponse(w, r, s3err.OwnershipControlsNotFoundError)
  367. return
  368. }
  369. ownership := string(v)
  370. result := &s3.PutBucketOwnershipControlsInput{
  371. OwnershipControls: &s3.OwnershipControls{
  372. Rules: []*s3.OwnershipControlsRule{
  373. {
  374. ObjectOwnership: &ownership,
  375. },
  376. },
  377. },
  378. }
  379. s3err.WriteAwsXMLResponse(w, r, http.StatusOK, result)
  380. }
  381. // DeleteBucketOwnershipControls https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteBucketOwnershipControls.html
  382. func (s3a *S3ApiServer) DeleteBucketOwnershipControls(w http.ResponseWriter, r *http.Request) {
  383. bucket, _ := s3_constants.GetBucketAndObject(r)
  384. glog.V(3).Infof("PutBucketOwnershipControls %s", bucket)
  385. errCode := s3a.checkAccessByOwnership(r, bucket)
  386. if errCode != s3err.ErrNone {
  387. s3err.WriteErrorResponse(w, r, errCode)
  388. return
  389. }
  390. bucketEntry, err := s3a.getEntry(s3a.option.BucketsPath, bucket)
  391. if err != nil {
  392. if err == filer_pb.ErrNotFound {
  393. s3err.WriteErrorResponse(w, r, s3err.ErrNoSuchBucket)
  394. return
  395. }
  396. s3err.WriteErrorResponse(w, r, s3err.ErrInternalError)
  397. return
  398. }
  399. _, ok := bucketEntry.Extended[s3_constants.ExtOwnershipKey]
  400. if !ok {
  401. s3err.WriteErrorResponse(w, r, s3err.OwnershipControlsNotFoundError)
  402. return
  403. }
  404. delete(bucketEntry.Extended, s3_constants.ExtOwnershipKey)
  405. err = s3a.updateEntry(s3a.option.BucketsPath, bucketEntry)
  406. if err != nil {
  407. s3err.WriteErrorResponse(w, r, s3err.ErrInternalError)
  408. return
  409. }
  410. emptyOwnershipControls := &s3.OwnershipControls{
  411. Rules: []*s3.OwnershipControlsRule{},
  412. }
  413. s3err.WriteAwsXMLResponse(w, r, http.StatusOK, emptyOwnershipControls)
  414. }