Skip to content

Commit

Permalink
SSE support for getObject (#1263)
Browse files Browse the repository at this point in the history
* SSE support for getObject

* SSE headers in getOpts for getObjects methods

---------

Co-authored-by: Johann Bournazel <johann.bournazel@protonmail.com>
  • Loading branch information
JohannGit and gargamelj authored Jun 10, 2024
1 parent 49c2157 commit 06758a5
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 19 deletions.
80 changes: 73 additions & 7 deletions docs/API.md
Original file line number Diff line number Diff line change
Expand Up @@ -824,11 +824,11 @@ Downloads an object as a stream.

**Parameters**

| Param | Type | Description |
| ------------ | -------- | ------------------------------------------------------------------------------------------- |
| `bucketName` | _string_ | Name of the bucket. |
| `objectName` | _string_ | Name of the object. |
| `getOpts` | _object_ | Version of the object in the form `{versionId:"my-versionId"}`. Default is `{}`. (optional) |
| Param | Type | Description |
| ------------ | -------- | ------------------------------------------------------ |
| `bucketName` | _string_ | Name of the bucket. |
| `objectName` | _string_ | Name of the object. |
| `getOpts` | _object_ | Options to get the object. Default is `{}`. (optional) |

**Return Value**

Expand Down Expand Up @@ -870,6 +870,28 @@ dataStream.on('error', function (err) {
})
```

**Example**

Get a Server Side Encrypted object.

```js
let size = 0
const dataStream = await minioClient.getObject('mybucket', 'photo.jpg', {
SSECustomerAlgorithm: 'AES256',
SSECustomerKey: 'YOUR_KEY',
SSECustomerKeyMD5: 'YOUR_MD5',
})
dataStream.on('data', function (chunk) {
size += chunk.length
})
dataStream.on('end', function () {
console.log('End. Total size = ' + size)
})
dataStream.on('error', function (err) {
console.log(err)
})
```

<a name="getPartialObject"></a>

### getPartialObject(bucketName, objectName, offset, length, getOpts[, callback])
Expand All @@ -884,7 +906,7 @@ Downloads the specified range bytes of an object as a stream.
| `objectName` | _string_ | Name of the object. |
| `offset` | _number_ | `offset` of the object from where the stream will start. |
| `length` | _number_ | `length` of the object that will be read in the stream (optional, if not specified we read the rest of the file from the offset). |
| `getOpts` | _object_ | Version of the object in the form `{versionId:'my-versionId'}`. Default is `{}`. (optional) |
| `getOpts` | _object_ | Options to get the object. Default is `{}`. (optional) |
| `callback(err, stream)` | _function_ | Callback is called with `err` in case of error. `stream` is the object content stream. If no callback is passed, a `Promise` is returned. |

**Return Value**
Expand Down Expand Up @@ -928,6 +950,28 @@ dataStream.on('error', function (err) {
})
```

**Example**
To get a Server Side Encrypted object.

```js
const versionedObjSize = 0
// reads 30 bytes from the offset 10.
const dataStream = await minioClient.getPartialObject('mybucket', 'photo.jpg', 10, 30, {
SSECustomerAlgorithm: 'AES256',
SSECustomerKey: 'YOUR_KEY',
SSECustomerKeyMD5: 'YOUR_MD5',
})
dataStream.on('data', function (chunk) {
versionedObjSize += chunk.length
})
dataStream.on('end', function () {
console.log('End. Total size = ' + versionedObjSize)
})
dataStream.on('error', function (err) {
console.log(err)
})
```

<a name="fGetObject"></a>

### fGetObject(bucketName, objectName, filePath, getOpts[, callback])
Expand All @@ -941,7 +985,7 @@ Downloads and saves the object as a file in the local filesystem.
| `bucketName` | _string_ | Name of the bucket. |
| `objectName` | _string_ | Name of the object. |
| `filePath` | _string_ | Path on the local filesystem to which the object data will be written. |
| `getOpts` | _object_ | Version of the object in the form `{versionId:'my-versionId'}`. Default is `{}`. (optional) |
| `getOpts` | _object_ | Options to get the object. Default is `{}`. (optional) |
| `callback(err)` | _function_ | Callback is called with `err` in case of error. If no callback is passed, a `Promise` is returned. |

**Return Value**
Expand Down Expand Up @@ -974,6 +1018,28 @@ minioClient.fGetObject(bucketName, objNameValue, './download/MyImage.jpg', { ver
})
```

**Example**
To Stream a Server Side Encrypted object into a file.

```js
minioClient.fGetObject(
bucketName,
objNameValue,
'./download/MyImage.jpg',
{
SSECustomerAlgorithm: 'AES256',
SSECustomerKey: 'YOUR_KEY',
SSECustomerKeyMD5: 'YOUR_MD5',
},
function (e) {
if (e) {
return console.log(e)
}
console.log('success')
},
)
```

<a name="putObject"></a>

### putObject(bucketName, objectName, stream, size, metaData[, callback])
Expand Down
33 changes: 21 additions & 12 deletions src/internal/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ import type {
CopyObjectResultV2,
EncryptionConfig,
GetObjectLegalHoldOptions,
GetObjectOpts,
GetObjectRetentionOpts,
IncompleteUploadedBucketItem,
IRequest,
Expand Down Expand Up @@ -107,7 +108,6 @@ import type {
Transport,
UploadedObjectInfo,
UploadPartConfig,
VersionIdentificator,
} from './type.ts'
import type { ListMultipartResult, UploadedPart } from './xml-parser.ts'
import {
Expand Down Expand Up @@ -972,11 +972,7 @@ export class TypedClient {
/**
* Callback is called with readable stream of the object content.
*/
async getObject(
bucketName: string,
objectName: string,
getOpts: VersionIdentificator = {},
): Promise<stream.Readable> {
async getObject(bucketName: string, objectName: string, getOpts: GetObjectOpts = {}): Promise<stream.Readable> {
if (!isValidBucketName(bucketName)) {
throw new errors.InvalidBucketNameError('Invalid bucket name: ' + bucketName)
}
Expand All @@ -999,7 +995,7 @@ export class TypedClient {
objectName: string,
offset: number,
length = 0,
getOpts: VersionIdentificator = {},
getOpts: GetObjectOpts = {},
): Promise<stream.Readable> {
if (!isValidBucketName(bucketName)) {
throw new errors.InvalidBucketNameError('Invalid bucket name: ' + bucketName)
Expand Down Expand Up @@ -1027,9 +1023,17 @@ export class TypedClient {
}
}

const headers: RequestHeaders = {}
if (range !== '') {
headers.range = range
const sseHeaders: Record<string, string> = {
...(getOpts.SSECustomerAlgorithm && {
'X-Amz-Server-Side-Encryption-Customer-Algorithm': getOpts.SSECustomerAlgorithm,
}),
...(getOpts.SSECustomerKey && { 'X-Amz-Server-Side-Encryption-Customer-Key': getOpts.SSECustomerKey }),
...(getOpts.SSECustomerKeyMD5 && { 'X-Amz-Server-Side-Encryption-Customer-Key-MD5': getOpts.SSECustomerKeyMD5 }),
}

const headers: RequestHeaders = {
...prependXAMZMeta(sseHeaders),
...(range !== '' && { range }),
}

const expectedStatusCodes = [200]
Expand All @@ -1051,7 +1055,12 @@ export class TypedClient {
* @param filePath - path to which the object data will be written to
* @param getOpts - Optional object get option
*/
async fGetObject(bucketName: string, objectName: string, filePath: string, getOpts: VersionIdentificator = {}) {
async fGetObject(
bucketName: string,
objectName: string,
filePath: string,
getOpts: GetObjectOpts = {},
): Promise<void> {
// Input validation.
if (!isValidBucketName(bucketName)) {
throw new errors.InvalidBucketNameError('Invalid bucket name: ' + bucketName)
Expand Down Expand Up @@ -1898,7 +1907,7 @@ export class TypedClient {
/**
* Get the tags associated with a bucket OR an object
*/
async getObjectTagging(bucketName: string, objectName: string, getOpts: VersionIdentificator = {}): Promise<Tag[]> {
async getObjectTagging(bucketName: string, objectName: string, getOpts: GetObjectOpts = {}): Promise<Tag[]> {
const method = 'GET'
let query = 'tagging'

Expand Down
6 changes: 6 additions & 0 deletions src/internal/type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ export type VersionIdentificator = {
versionId?: string
}

export type GetObjectOpts = VersionIdentificator & {
SSECustomerAlgorithm?: string
SSECustomerKey?: string
SSECustomerKeyMD5?: string
}

export type Binary = string | Buffer

// nodejs IncomingHttpHeaders is Record<string, string | string[]>, but it's actually this:
Expand Down

0 comments on commit 06758a5

Please sign in to comment.