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.

251 lines
7.3 KiB

6 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
  1. package s3api
  2. import (
  3. "fmt"
  4. "net/http"
  5. "net/url"
  6. "strconv"
  7. "strings"
  8. "github.com/aws/aws-sdk-go/aws"
  9. "github.com/aws/aws-sdk-go/service/s3"
  10. )
  11. const (
  12. maxObjectListSizeLimit = 10000 // Limit number of objects in a listObjectsResponse.
  13. maxUploadsList = 10000 // Limit number of uploads in a listUploadsResponse.
  14. maxPartsList = 10000 // Limit number of parts in a listPartsResponse.
  15. globalMaxPartID = 100000
  16. )
  17. // NewMultipartUploadHandler - New multipart upload.
  18. func (s3a *S3ApiServer) NewMultipartUploadHandler(w http.ResponseWriter, r *http.Request) {
  19. bucket, object := getBucketAndObject(r)
  20. response, errCode := s3a.createMultipartUpload(&s3.CreateMultipartUploadInput{
  21. Bucket: aws.String(bucket),
  22. Key: objectKey(aws.String(object)),
  23. })
  24. if errCode != ErrNone {
  25. writeErrorResponse(w, errCode, r.URL)
  26. return
  27. }
  28. // println("NewMultipartUploadHandler", string(encodeResponse(response)))
  29. writeSuccessResponseXML(w, encodeResponse(response))
  30. }
  31. // CompleteMultipartUploadHandler - Completes multipart upload.
  32. func (s3a *S3ApiServer) CompleteMultipartUploadHandler(w http.ResponseWriter, r *http.Request) {
  33. bucket, object := getBucketAndObject(r)
  34. // Get upload id.
  35. uploadID, _, _, _ := getObjectResources(r.URL.Query())
  36. response, errCode := s3a.completeMultipartUpload(&s3.CompleteMultipartUploadInput{
  37. Bucket: aws.String(bucket),
  38. Key: objectKey(aws.String(object)),
  39. UploadId: aws.String(uploadID),
  40. })
  41. // println("CompleteMultipartUploadHandler", string(encodeResponse(response)), errCode)
  42. if errCode != ErrNone {
  43. writeErrorResponse(w, errCode, r.URL)
  44. return
  45. }
  46. writeSuccessResponseXML(w, encodeResponse(response))
  47. }
  48. // AbortMultipartUploadHandler - Aborts multipart upload.
  49. func (s3a *S3ApiServer) AbortMultipartUploadHandler(w http.ResponseWriter, r *http.Request) {
  50. bucket, object := getBucketAndObject(r)
  51. // Get upload id.
  52. uploadID, _, _, _ := getObjectResources(r.URL.Query())
  53. response, errCode := s3a.abortMultipartUpload(&s3.AbortMultipartUploadInput{
  54. Bucket: aws.String(bucket),
  55. Key: objectKey(aws.String(object)),
  56. UploadId: aws.String(uploadID),
  57. })
  58. if errCode != ErrNone {
  59. writeErrorResponse(w, errCode, r.URL)
  60. return
  61. }
  62. // println("AbortMultipartUploadHandler", string(encodeResponse(response)))
  63. writeSuccessResponseXML(w, encodeResponse(response))
  64. }
  65. // ListMultipartUploadsHandler - Lists multipart uploads.
  66. func (s3a *S3ApiServer) ListMultipartUploadsHandler(w http.ResponseWriter, r *http.Request) {
  67. bucket, _ := getBucketAndObject(r)
  68. prefix, keyMarker, uploadIDMarker, delimiter, maxUploads, encodingType := getBucketMultipartResources(r.URL.Query())
  69. if maxUploads < 0 {
  70. writeErrorResponse(w, ErrInvalidMaxUploads, r.URL)
  71. return
  72. }
  73. if keyMarker != "" {
  74. // Marker not common with prefix is not implemented.
  75. if !strings.HasPrefix(keyMarker, prefix) {
  76. writeErrorResponse(w, ErrNotImplemented, r.URL)
  77. return
  78. }
  79. }
  80. response, errCode := s3a.listMultipartUploads(&s3.ListMultipartUploadsInput{
  81. Bucket: aws.String(bucket),
  82. Delimiter: aws.String(delimiter),
  83. EncodingType: aws.String(encodingType),
  84. KeyMarker: aws.String(keyMarker),
  85. MaxUploads: aws.Int64(int64(maxUploads)),
  86. Prefix: aws.String(prefix),
  87. UploadIdMarker: aws.String(uploadIDMarker),
  88. })
  89. if errCode != ErrNone {
  90. writeErrorResponse(w, errCode, r.URL)
  91. return
  92. }
  93. // TODO handle encodingType
  94. // println("ListMultipartUploadsHandler", string(encodeResponse(response)))
  95. writeSuccessResponseXML(w, encodeResponse(response))
  96. }
  97. // ListObjectPartsHandler - Lists object parts in a multipart upload.
  98. func (s3a *S3ApiServer) ListObjectPartsHandler(w http.ResponseWriter, r *http.Request) {
  99. bucket, object := getBucketAndObject(r)
  100. uploadID, partNumberMarker, maxParts, _ := getObjectResources(r.URL.Query())
  101. if partNumberMarker < 0 {
  102. writeErrorResponse(w, ErrInvalidPartNumberMarker, r.URL)
  103. return
  104. }
  105. if maxParts < 0 {
  106. writeErrorResponse(w, ErrInvalidMaxParts, r.URL)
  107. return
  108. }
  109. response, errCode := s3a.listObjectParts(&s3.ListPartsInput{
  110. Bucket: aws.String(bucket),
  111. Key: objectKey(aws.String(object)),
  112. MaxParts: aws.Int64(int64(maxParts)),
  113. PartNumberMarker: aws.Int64(int64(partNumberMarker)),
  114. UploadId: aws.String(uploadID),
  115. })
  116. if errCode != ErrNone {
  117. writeErrorResponse(w, errCode, r.URL)
  118. return
  119. }
  120. // println("ListObjectPartsHandler", string(encodeResponse(response)))
  121. writeSuccessResponseXML(w, encodeResponse(response))
  122. }
  123. // PutObjectPartHandler - Put an object part in a multipart upload.
  124. func (s3a *S3ApiServer) PutObjectPartHandler(w http.ResponseWriter, r *http.Request) {
  125. bucket, _ := getBucketAndObject(r)
  126. uploadID := r.URL.Query().Get("uploadId")
  127. exists, err := s3a.exists(s3a.genUploadsFolder(bucket), uploadID, true)
  128. if !exists {
  129. writeErrorResponse(w, ErrNoSuchUpload, r.URL)
  130. return
  131. }
  132. partIDString := r.URL.Query().Get("partNumber")
  133. partID, err := strconv.Atoi(partIDString)
  134. if err != nil {
  135. writeErrorResponse(w, ErrInvalidPart, r.URL)
  136. return
  137. }
  138. if partID > globalMaxPartID {
  139. writeErrorResponse(w, ErrInvalidMaxParts, r.URL)
  140. return
  141. }
  142. rAuthType := getRequestAuthType(r)
  143. dataReader := r.Body
  144. var s3ErrCode ErrorCode
  145. switch rAuthType {
  146. case authTypeStreamingSigned:
  147. dataReader, s3ErrCode = s3a.iam.newSignV4ChunkedReader(r)
  148. case authTypeSignedV2, authTypePresignedV2:
  149. _, s3ErrCode = s3a.iam.isReqAuthenticatedV2(r)
  150. case authTypePresigned, authTypeSigned:
  151. _, s3ErrCode = s3a.iam.reqSignatureV4Verify(r)
  152. }
  153. if s3ErrCode != ErrNone {
  154. writeErrorResponse(w, s3ErrCode, r.URL)
  155. return
  156. }
  157. defer dataReader.Close()
  158. uploadUrl := fmt.Sprintf("http://%s%s/%s/%04d.part?collection=%s",
  159. s3a.option.Filer, s3a.genUploadsFolder(bucket), uploadID, partID-1, bucket)
  160. etag, errCode := s3a.putToFiler(r, uploadUrl, dataReader)
  161. if errCode != ErrNone {
  162. writeErrorResponse(w, errCode, r.URL)
  163. return
  164. }
  165. setEtag(w, etag)
  166. writeSuccessResponseEmpty(w)
  167. }
  168. func (s3a *S3ApiServer) genUploadsFolder(bucket string) string {
  169. return fmt.Sprintf("%s/%s/.uploads", s3a.option.BucketsPath, bucket)
  170. }
  171. // Parse bucket url queries for ?uploads
  172. func getBucketMultipartResources(values url.Values) (prefix, keyMarker, uploadIDMarker, delimiter string, maxUploads int, encodingType string) {
  173. prefix = values.Get("prefix")
  174. keyMarker = values.Get("key-marker")
  175. uploadIDMarker = values.Get("upload-id-marker")
  176. delimiter = values.Get("delimiter")
  177. if values.Get("max-uploads") != "" {
  178. maxUploads, _ = strconv.Atoi(values.Get("max-uploads"))
  179. } else {
  180. maxUploads = maxUploadsList
  181. }
  182. encodingType = values.Get("encoding-type")
  183. return
  184. }
  185. // Parse object url queries
  186. func getObjectResources(values url.Values) (uploadID string, partNumberMarker, maxParts int, encodingType string) {
  187. uploadID = values.Get("uploadId")
  188. partNumberMarker, _ = strconv.Atoi(values.Get("part-number-marker"))
  189. if values.Get("max-parts") != "" {
  190. maxParts, _ = strconv.Atoi(values.Get("max-parts"))
  191. } else {
  192. maxParts = maxPartsList
  193. }
  194. encodingType = values.Get("encoding-type")
  195. return
  196. }
  197. type byCompletedPartNumber []*s3.CompletedPart
  198. func (a byCompletedPartNumber) Len() int { return len(a) }
  199. func (a byCompletedPartNumber) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
  200. func (a byCompletedPartNumber) Less(i, j int) bool { return *a[i].PartNumber < *a[j].PartNumber }