/* 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) })], ['presigned PUT then DELETE', () => Promise.resolve('put-target-' + Math.random()).then((objectName) => { return MakeRequest('PUT', service.getSignedUrl('putObject', { Bucket: 'private-with-cors', Key: objectName, ContentType: 'application/octet-stream' // Consciously go for an unsigned payload }), {'Content-Type': 'application/octet-stream'}, 'test') .then(HasStatus(200, 'OK')) .then(CheckS3Headers) .then(HasHeaders({ 'Content-Type': 'text/html; charset=UTF-8', Etag: '"098f6bcd4621d373cade4e832627b4f6"' })) .then(HasNoBody) .then((resp) => { return MakeRequest('DELETE', service.getSignedUrl('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' }))