swift/test/cors/test-s3-obj.js
Tim Burke 27a734c78a s3api: Allow CORS preflight requests
Unfortunately, we can't identify the user, so we can't map to an
account, so we can't respect whatever CORS metadata might be set on the
container.

As a result, the allowed origins must be configured cluster-wide. Add a
new config option, cors_preflight_allow_origin, for that; default it
to blank (ie, deny preflights from all origins, preserving existing
behavior), but allow either a comma-separated list of origins or
* (to allow all origins).

Change-Id: I985143bf03125a05792e79bc5e5f83722d6431b3
Co-Authored-By: Matthew Oliver <matt@oliver.net.au>
2021-03-15 13:52:05 -07:00

219 lines
6.6 KiB
JavaScript

/* global PARAMS */
import {
runTests,
MakeRequest,
HasStatus,
HasHeaders,
DoesNotHaveHeaders,
HasNoBody,
BodyHasLength,
CorsBlocked
} from './harness.js'
import './vendor/aws-sdk-2.829.0.min.js'
const AWS = window.AWS
function CheckTransactionIdHeaders (resp) {
return Promise.resolve(resp)
.then(HasHeaders([
'x-amz-request-id',
'x-amz-id-2',
'X-Openstack-Request-Id',
'X-Trans-Id'
]))
.then((resp) => {
const txnId = resp.getResponseHeader('X-Openstack-Request-Id')
return Promise.resolve(resp)
.then(HasHeaders({
'x-amz-request-id': txnId,
'x-amz-id-2': txnId,
'X-Trans-Id': txnId
}))
})
}
function CheckS3Headers (resp) {
return Promise.resolve(resp)
.then(HasHeaders([
'Last-Modified',
'Content-Type'
]))
.then(CheckTransactionIdHeaders)
.then(DoesNotHaveHeaders([
'X-Timestamp',
'Accept-Ranges',
'Access-Control-Allow-Origin',
'Access-Control-Expose-Headers',
'Date',
// Hmmm....
'Content-Range',
'X-Account-Bytes-Used',
'X-Account-Container-Count',
'X-Account-Object-Count',
'X-Container-Bytes-Used',
'X-Container-Object-Count'
]))
}
function MakeS3Request (service, operation, params) {
return new Promise((resolve, reject) => {
const s3req = service[operation](params)
// Don't *actually* send it
s3req.removeListener('send', AWS.EventListeners.Core.SEND)
// Instead, copy method, path, headers over to a new test-harness request
s3req.addListener('send', function () {
const endpoint = s3req.httpRequest.endpoint
const signedReq = s3req.httpRequest
const filteredHeaders = {}
for (const header of Object.keys(signedReq.headers)) {
if (header === 'Host' || header === 'Content-Length') {
continue // browser won't let you send these anyway
}
filteredHeaders[header] = signedReq.headers[header]
}
resolve(MakeRequest(
signedReq.method,
endpoint.protocol + '//' + endpoint.host + signedReq.path,
filteredHeaders,
signedReq.body
))
})
s3req.send()
})
}
function makeTests (params) {
const service = new AWS.S3(params)
return [
['presigned GET, no CORS',
() => MakeRequest('GET', service.getSignedUrl('getObject', {
Bucket: 'public-no-cors',
Key: 'obj'
}))
.then(CorsBlocked)],
['presigned HEAD, no CORS',
() => MakeRequest('HEAD', service.getSignedUrl('headObject', {
Bucket: 'public-no-cors',
Key: 'obj'
}))
.then(CorsBlocked)],
['presigned GET, object exists',
() => MakeRequest('GET', service.getSignedUrl('getObject', {
Bucket: 'private-with-cors',
Key: 'obj'
}))
.then(HasStatus(200, 'OK'))
.then(CheckS3Headers)
.then(HasHeaders(['x-amz-meta-mtime']))
.then(DoesNotHaveHeaders(['X-Object-Meta-Mtime']))
.then(HasHeaders({
'Content-Type': 'application/octet-stream',
Etag: '"0f343b0931126a20f133d67c2b018a3b"'
}))
.then(BodyHasLength(1024))],
['presigned HEAD, object exists',
() => MakeRequest('HEAD', service.getSignedUrl('headObject', {
Bucket: 'private-with-cors',
Key: 'obj'
}))
.then(HasStatus(200, 'OK'))
.then(CheckS3Headers)
.then(HasHeaders(['x-amz-meta-mtime']))
.then(DoesNotHaveHeaders(['X-Object-Meta-Mtime']))
.then(HasHeaders({
'Content-Type': 'application/octet-stream',
Etag: '"0f343b0931126a20f133d67c2b018a3b"'
}))
.then(HasNoBody)],
['GET, object exists',
() => MakeS3Request(service, 'getObject', {
Bucket: 'private-with-cors',
Key: 'obj'
})
.then(HasStatus(200, 'OK'))
.then(CheckS3Headers)
.then(HasHeaders(['x-amz-meta-mtime']))
.then(DoesNotHaveHeaders(['X-Object-Meta-Mtime']))
.then(HasHeaders({
'Content-Type': 'application/octet-stream',
Etag: '"0f343b0931126a20f133d67c2b018a3b"'
}))
.then(BodyHasLength(1024))],
['PUT then DELETE',
() => Promise.resolve('put-target-' + Math.random()).then((objectName) => {
return MakeS3Request(service, 'putObject', {
Bucket: 'private-with-cors',
Key: objectName,
Body: 'test'
})
.then(HasStatus(200, 'OK'))
.then(CheckS3Headers)
.then(HasHeaders({
'Content-Type': 'text/html; charset=UTF-8',
Etag: '"098f6bcd4621d373cade4e832627b4f6"'
}))
.then(HasNoBody)
.then((resp) => {
return MakeS3Request(service, 'deleteObject', {
Bucket: 'private-with-cors',
Key: objectName
})
})
.then(HasStatus(204, 'No Content'))
.then(CheckTransactionIdHeaders)
.then(HasNoBody)
})],
['GET If-Match matching',
() => MakeS3Request(service, 'getObject', {
Bucket: 'private-with-cors',
Key: 'obj',
IfMatch: '0f343b0931126a20f133d67c2b018a3b'
})
.then(HasStatus(200, 'OK'))
.then(CheckS3Headers)
.then(HasHeaders(['x-amz-meta-mtime']))
.then(DoesNotHaveHeaders(['X-Object-Meta-Mtime']))
.then(HasHeaders({
'Content-Type': 'application/octet-stream',
Etag: '"0f343b0931126a20f133d67c2b018a3b"'
}))
.then(BodyHasLength(1024))],
['GET Range',
() => MakeS3Request(service, 'getObject', {
Bucket: 'private-with-cors',
Key: 'obj',
Range: 'bytes=100-199'
})
.then(HasStatus(206, 'Partial Content'))
.then(CheckS3Headers)
.then(HasHeaders(['x-amz-meta-mtime']))
.then(DoesNotHaveHeaders(['X-Object-Meta-Mtime']))
.then(HasHeaders({
'Content-Type': 'application/octet-stream',
Etag: '"0f343b0931126a20f133d67c2b018a3b"'
}))
.then(BodyHasLength(100))]
]
}
runTests('s3 obj (v2)', makeTests({
endpoint: PARAMS.S3_ENDPOINT || 'http://localhost:8080',
region: PARAMS.S3_REGION || 'us-east-1',
accessKeyId: PARAMS.S3_USER || 'test:tester',
secretAccessKey: PARAMS.S3_KEY || 'testing',
s3ForcePathStyle: true,
signatureVersion: 'v2'
}))
runTests('s3 obj (v4)', makeTests({
endpoint: PARAMS.S3_ENDPOINT || 'http://localhost:8080',
region: PARAMS.S3_REGION || 'us-east-1',
accessKeyId: PARAMS.S3_USER || 'test:tester',
secretAccessKey: PARAMS.S3_KEY || 'testing',
s3ForcePathStyle: true,
signatureVersion: 'v4'
}))