diff --git a/docs/design/core/presignedURL-Get/DecisionLog.md b/docs/design/core/presignedURL-Get/DecisionLog.md index afd5b033a00a..b37a7324ae1c 100644 --- a/docs/design/core/presignedURL-Get/DecisionLog.md +++ b/docs/design/core/presignedURL-Get/DecisionLog.md @@ -69,3 +69,8 @@ Initially considered separate discovery request (bytes=0-0) followed by download 1. **API Names**: Finalize `downloadWithPresignedUrl` and `downloadFileWithPresignedUrl` for Transfer Manager methods during Surface API Review later. 2. **Pause/Resume Support**: Decided not to support pause/resume capability for presigned URL downloads, maintaining consistency with AWS SDK for Java v1 which also lacks this feature for presigned URLs. + +## API Surface Area Review Decision: 05/28/2026 + +### Decision Addressed +Changed the return type of downloadFileWithPresignedUrl from FileDownload to a new PresignedFileDownload type. FileDownload exposes pause() which is not supported for presigned URL downloads — introducing PresignedFileDownload makes this a compile-time guarantee rather than a runtime UnsupportedOperationException. diff --git a/docs/design/core/presignedURL-Get/Design.md b/docs/design/core/presignedURL-Get/Design.md index d2cd1f691229..127e7653f396 100644 --- a/docs/design/core/presignedURL-Get/Design.md +++ b/docs/design/core/presignedURL-Get/Design.md @@ -39,7 +39,7 @@ AsyncPresignedUrlExtension presignExtension = s3Client.presignedUrlExtension(); // Create presigned URL request PresignedUrlDownloadRequest request = PresignedUrlDownloadRequest.builder() .presignedUrl(presignedUrl) - .range("range=0-1024") + .range("bytes=0-1024") .build(); // Async usage @@ -72,7 +72,7 @@ CompletableFuture> response = multipartClient.presignedUrlExtension().getObject(request, AsyncResponseTransformer.toBytes()); ``` -The multipart implementation uses Range headers (e.g., `bytes=0-8388607`) instead of partNumber parameters to preserve presigned URL signatures. The first request downloads the initial part while discovering total object size from the Content-Range header. +The multipart implementation uses Range headers (e.g., `bytes=0-8388607`) instead of partNumber parameters to preserve presigned URL signatures. The first request downloads the initial part while discovering total object size from the Content-Range header. Subsequent parts include an `If-Match` header with the ETag captured from the first response to detect object mutation mid-download. Each part response is validated to ensure Content-Range alignment and Content-Length match expected values. ### AsyncPresignedUrlExtension Interface @@ -111,10 +111,11 @@ public final class PresignedUrlDownloadRequest private final URL presignedUrl; private final String range; + private final String ifMatch; - // Standard getters: presignedUrl(), range() + // Standard getters: presignedUrl(), range(), ifMatch() // Standard builder methods: builder(), toBuilder() - // Standard Builder class with presignedUrl(), range() setter methods + // Standard Builder class with presignedUrl(), range(), ifMatch() setter methods } ``` @@ -126,7 +127,7 @@ The S3TransferManager extends support for presigned URL downloads, providing hig ```java // File-based presigned URL download -FileDownload download = transferManager.downloadFileWithPresignedUrl( +PresignedFileDownload download = transferManager.downloadFileWithPresignedUrl( PresignedDownloadFileRequest.builder() .presignedUrlDownloadRequest(PresignedUrlDownloadRequest.builder() .presignedUrl(presignedUrl)