Skip to content

Commit

Permalink
fix: Fixing presigned URL for Multi part upload
Browse files Browse the repository at this point in the history
  • Loading branch information
sebaland committed Sep 10, 2024
1 parent eca7cfe commit e46ba05
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ extension UploadPartInput {
.withRegion(value: config.region)
.withSigningName(value: "s3")
.withSigningRegion(value: config.signingRegion)
.withUnsignedPayloadTrait(value: true)
.build()
let builder = ClientRuntime.OrchestratorBuilder<UploadPartInput, UploadPartOutput, SmithyHTTPAPI.HTTPRequest, SmithyHTTPAPI.HTTPResponse>()
config.interceptorProviders.forEach { provider in
Expand All @@ -62,6 +63,7 @@ extension UploadPartInput {
builder.selectAuthScheme(ClientRuntime.AuthSchemeMiddleware<UploadPartOutput>())
builder.interceptors.add(AWSClientRuntime.AWSS3ErrorWith200StatusXMLMiddleware<UploadPartInput, UploadPartOutput>())
builder.interceptors.add(AWSClientRuntime.FlexibleChecksumsRequestMiddleware<UploadPartInput, UploadPartOutput>(checksumAlgorithm: input.checksumAlgorithm?.rawValue))
builder.serialize(UploadPartPresignedMiddleware())
var metricsAttributes = Smithy.Attributes()
metricsAttributes.set(key: ClientRuntime.OrchestratorMetricsAttributesKeys.service, value: "S3")
metricsAttributes.set(key: ClientRuntime.OrchestratorMetricsAttributesKeys.method, value: "UploadPart")
Expand All @@ -76,33 +78,34 @@ extension UploadPartInput {
.build()
return try await op.presignRequest(input: input).endpoint.url
}
}

static func urlPathProvider(_ value: UploadPartInput) -> Swift.String? {
guard let key = value.key else {
return nil
}
return "/\(key.urlPercentEncoding(encodeForwardSlash: false))"
}
struct UploadPartPresignedMiddleware: Smithy.RequestMessageSerializer {
typealias InputType = UploadPartInput
typealias RequestType = SmithyHTTPAPI.HTTPRequest

}
let id: Swift.String = "UploadPartPresignedMiddleware"

extension UploadPartInput {
func apply(input: InputType, builder: SmithyHTTPAPI.HTTPRequestBuilder, attributes: Smithy.Context) throws {
builder.withQueryItem(.init(
name: "x-id",
value: "UploadPart")
)

static func queryItemProvider(_ value: UploadPartInput) throws -> [URIQueryItem] {
var items = [URIQueryItem]()
items.append(URIQueryItem(name: "x-id", value: "UploadPart"))
guard let partNumber = value.partNumber else {
let message = "Creating a URL Query Item failed. partNumber is required and must not be nil."
throw ClientError.unknownError(message)
guard let partNumber = input.partNumber else {
throw ClientError.invalidValue("partNumber is required and must not be nil.")
}
let partNumberQueryItem = URIQueryItem(name: "partNumber".urlPercentEncoding(), value: Swift.String(partNumber).urlPercentEncoding())
items.append(partNumberQueryItem)
guard let uploadId = value.uploadId else {
let message = "Creating a URL Query Item failed. uploadId is required and must not be nil."
throw ClientError.unknownError(message)
builder.withQueryItem(.init(
name: "partNumber".urlPercentEncoding(),
value: Swift.String(partNumber).urlPercentEncoding())
)

guard let uploadId = input.uploadId else {
throw ClientError.invalidValue("uploadId is required and must not be nil.")
}
let uploadIdQueryItem = URIQueryItem(name: "uploadId".urlPercentEncoding(), value: Swift.String(uploadId).urlPercentEncoding())
items.append(uploadIdQueryItem)
return items
builder.withQueryItem(.init(
name: "uploadId".urlPercentEncoding(),
value: Swift.String(uploadId).urlPercentEncoding())
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ class StorageMultipartUploadSession {
private let onEvent: AWSS3StorageServiceBehavior.StorageServiceMultiPartUploadEventHandler

private let transferTask: StorageTransferTask
private var cancelationFailure: (any Error)?

init(client: StorageMultipartUploadClient,
bucket: String,
Expand Down Expand Up @@ -244,10 +245,15 @@ class StorageMultipartUploadSession {
}
case .completed:
onEvent(.completed(()))
case .aborting:
case .aborting(_, let error):
cancelationFailure = error
try abort()
case .aborted:
onEvent(.completed(()))
case .aborted(_, let error):
if let cancelationFailure {
onEvent(.failed(StorageError(error: cancelationFailure)))
} else {
onEvent(.failed(StorageError.unknown("Unable to upload", error)))
}
case .failed(_, _, let error):
onEvent(.failed(StorageError(error: error)))
default:
Expand Down Expand Up @@ -331,6 +337,11 @@ class StorageMultipartUploadSession {
let index = partNumber - 1
parts[index] = .pending(bytes: part.bytes)
multipartUpload = .parts(uploadId: uploadId, uploadFile: uploadFile, partSize: partSize, parts: parts)
let remainingParts = parts.filter({ $0.inProgress })
if remainingParts.isEmpty {
// If there are no remaining parts in progress, manually trigger the reupload
try client.uploadPart(partNumber: partNumber, multipartUpload: multipartUpload, subTask: createSubTask(partNumber: partNumber))
}
} else {
fatalError("Invalid state")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,17 @@ extension StorageServiceSessionDelegate: URLSessionTaskDelegate {
if response.isErrorRetriable {
logURLSessionActivity("Task can be retried.")
}
// For multipart uploads, we need to handle the upload part failure
if case .multiPartUploadPart(let uploadId, let partNumber) = transferTask.transferType,
let multipartUploadSession = storageService.findMultipartUploadSession(uploadId: uploadId),
!multipartUploadSession.isAborted {
multipartUploadSession.handle(
uploadPartEvent: .failed(
partNumber: partNumber,
error: responseError
)
)
}
return
}

Expand Down

0 comments on commit e46ba05

Please sign in to comment.