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.

116 lines
3.0 KiB

7 years ago
7 years ago
  1. package s3api
  2. import (
  3. "context"
  4. "fmt"
  5. "github.com/chrislusf/seaweedfs/weed/filer2"
  6. "github.com/chrislusf/seaweedfs/weed/glog"
  7. "github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
  8. "github.com/gorilla/mux"
  9. "net/http"
  10. "net/url"
  11. "path/filepath"
  12. "strconv"
  13. "time"
  14. )
  15. const (
  16. maxObjectListSizeLimit = 1000 // Limit number of objects in a listObjectsResponse.
  17. )
  18. func (s3a *S3ApiServer) ListObjectsV1Handler(w http.ResponseWriter, r *http.Request) {
  19. // https://docs.aws.amazon.com/AmazonS3/latest/API/RESTBucketGET.html
  20. // collect parameters
  21. vars := mux.Vars(r)
  22. bucket := vars["bucket"]
  23. originalPrefix, marker, delimiter, maxKeys := getListObjectsV1Args(r.URL.Query())
  24. if maxKeys < 0 {
  25. writeErrorResponse(w, ErrInvalidMaxKeys, r.URL)
  26. return
  27. }
  28. if delimiter != "" && delimiter != "/" {
  29. writeErrorResponse(w, ErrNotImplemented, r.URL)
  30. }
  31. // convert full path prefix into directory name and prefix for entry name
  32. dir, prefix := filepath.Split(originalPrefix)
  33. // check filer
  34. var response ListBucketResponse
  35. err := s3a.withFilerClient(func(client filer_pb.SeaweedFilerClient) error {
  36. request := &filer_pb.ListEntriesRequest{
  37. Directory: fmt.Sprintf("%s/%s/%s", s3a.option.BucketsPath, bucket, dir),
  38. Prefix: prefix,
  39. Limit: uint32(maxKeys),
  40. StartFromFileName: marker,
  41. InclusiveStartFrom: false,
  42. }
  43. glog.V(4).Infof("read directory: %v", request)
  44. resp, err := client.ListEntries(context.Background(), request)
  45. if err != nil {
  46. return fmt.Errorf("list buckets: %v", err)
  47. }
  48. var contents []ListEntry
  49. var commonPrefixes []PrefixEntry
  50. for _, entry := range resp.Entries {
  51. if entry.IsDirectory {
  52. commonPrefixes = append(commonPrefixes, PrefixEntry{
  53. Prefix: fmt.Sprintf("%s%s/", dir, entry.Name),
  54. })
  55. } else {
  56. contents = append(contents, ListEntry{
  57. Key: fmt.Sprintf("%s%s", dir, entry.Name),
  58. LastModified: time.Unix(entry.Attributes.Mtime, 0),
  59. ETag: "", // TODO add etag
  60. Size: int64(filer2.TotalSize(entry.Chunks)),
  61. Owner: CanonicalUser{
  62. ID: fmt.Sprintf("%d", entry.Attributes.Uid),
  63. },
  64. StorageClass: StorageClass("STANDARD"),
  65. })
  66. }
  67. }
  68. response = ListBucketResponse{
  69. ListBucketResponse: ListBucketResult{
  70. Name: bucket,
  71. Prefix: originalPrefix,
  72. Marker: marker, // TODO
  73. NextMarker: "", // TODO
  74. MaxKeys: maxKeys,
  75. Delimiter: delimiter,
  76. IsTruncated: false, // TODO
  77. Contents: contents,
  78. CommonPrefixes: commonPrefixes,
  79. },
  80. }
  81. return nil
  82. })
  83. if err != nil {
  84. writeErrorResponse(w, ErrInternalError, r.URL)
  85. return
  86. }
  87. writeSuccessResponseXML(w, encodeResponse(response))
  88. }
  89. func getListObjectsV1Args(values url.Values) (prefix, marker, delimiter string, maxkeys int) {
  90. prefix = values.Get("prefix")
  91. marker = values.Get("marker")
  92. delimiter = values.Get("delimiter")
  93. if values.Get("max-keys") != "" {
  94. maxkeys, _ = strconv.Atoi(values.Get("max-keys"))
  95. } else {
  96. maxkeys = maxObjectListSizeLimit
  97. }
  98. return
  99. }