Bladeren bron

@uppy/aws-s3-multipart: allow `companionHeaders` to be modified with `setOptions` (#3770)

Paulo Lemos Neto 2 jaren geleden
bovenliggende
commit
6514e43e5d

+ 23 - 6
packages/@uppy/aws-s3-multipart/src/index.js

@@ -20,12 +20,14 @@ function assertServerError (res) {
 export default class AwsS3Multipart extends BasePlugin {
   static VERSION = packageJson.version
 
+  #client
+
   constructor (uppy, opts) {
     super(uppy, opts)
     this.type = 'uploader'
     this.id = this.opts.id || 'AwsS3Multipart'
     this.title = 'AWS S3 Multipart'
-    this.client = new RequestClient(uppy, opts)
+    this.#client = new RequestClient(uppy, opts)
 
     const defaultOptions = {
       timeout: 30 * 1000,
@@ -36,6 +38,7 @@ export default class AwsS3Multipart extends BasePlugin {
       prepareUploadParts: this.prepareUploadParts.bind(this),
       abortMultipartUpload: this.abortMultipartUpload.bind(this),
       completeMultipartUpload: this.completeMultipartUpload.bind(this),
+      companionHeaders: {},
     }
 
     this.opts = { ...defaultOptions, ...opts }
@@ -49,6 +52,13 @@ export default class AwsS3Multipart extends BasePlugin {
     this.uploaderSockets = Object.create(null)
   }
 
+  [Symbol.for('uppy test: getClient')] () { return this.#client }
+
+  // TODO: remove getter and setter for #client on the next major release
+  get client () { return this.#client }
+
+  set client (client) { this.#client = client }
+
   /**
    * Clean up all references for a file's upload: the MultipartUploader instance,
    * any events related to the file, and the Companion WebSocket connection.
@@ -88,7 +98,7 @@ export default class AwsS3Multipart extends BasePlugin {
       }
     })
 
-    return this.client.post('s3/multipart', {
+    return this.#client.post('s3/multipart', {
       filename: file.name,
       type: file.type,
       metadata,
@@ -99,7 +109,7 @@ export default class AwsS3Multipart extends BasePlugin {
     this.assertHost('listParts')
 
     const filename = encodeURIComponent(key)
-    return this.client.get(`s3/multipart/${uploadId}?key=${filename}`)
+    return this.#client.get(`s3/multipart/${uploadId}?key=${filename}`)
       .then(assertServerError)
   }
 
@@ -107,7 +117,7 @@ export default class AwsS3Multipart extends BasePlugin {
     this.assertHost('prepareUploadParts')
 
     const filename = encodeURIComponent(key)
-    return this.client.get(`s3/multipart/${uploadId}/batch?key=${filename}&partNumbers=${partNumbers.join(',')}`)
+    return this.#client.get(`s3/multipart/${uploadId}/batch?key=${filename}&partNumbers=${partNumbers.join(',')}`)
       .then(assertServerError)
   }
 
@@ -116,7 +126,7 @@ export default class AwsS3Multipart extends BasePlugin {
 
     const filename = encodeURIComponent(key)
     const uploadIdEnc = encodeURIComponent(uploadId)
-    return this.client.post(`s3/multipart/${uploadIdEnc}/complete?key=${filename}`, { parts })
+    return this.#client.post(`s3/multipart/${uploadIdEnc}/complete?key=${filename}`, { parts })
       .then(assertServerError)
   }
 
@@ -125,7 +135,7 @@ export default class AwsS3Multipart extends BasePlugin {
 
     const filename = encodeURIComponent(key)
     const uploadIdEnc = encodeURIComponent(uploadId)
-    return this.client.delete(`s3/multipart/${uploadIdEnc}?key=${filename}`)
+    return this.#client.delete(`s3/multipart/${uploadIdEnc}?key=${filename}`)
       .then(assertServerError)
   }
 
@@ -436,6 +446,11 @@ export default class AwsS3Multipart extends BasePlugin {
     return Promise.all(promises)
   }
 
+  #setCompanionHeaders = () => {
+    this.#client.setCompanionHeaders(this.opts.companionHeaders)
+    return Promise.resolve()
+  }
+
   onFileRemove (fileID, cb) {
     this.uploaderEvents[fileID].on('file-removed', (file) => {
       if (fileID === file.id) cb(file.id)
@@ -495,6 +510,7 @@ export default class AwsS3Multipart extends BasePlugin {
         resumableUploads: true,
       },
     })
+    this.uppy.addPreProcessor(this.#setCompanionHeaders)
     this.uppy.addUploader(this.upload)
   }
 
@@ -506,6 +522,7 @@ export default class AwsS3Multipart extends BasePlugin {
         resumableUploads: false,
       },
     })
+    this.uppy.removePreProcessor(this.#setCompanionHeaders)
     this.uppy.removeUploader(this.upload)
   }
 }

+ 31 - 0
packages/@uppy/aws-s3-multipart/src/index.test.js

@@ -227,4 +227,35 @@ describe('AwsS3Multipart', () => {
       expect(awsS3Multipart.opts.prepareUploadParts.mock.calls.length).toEqual(2)
     })
   })
+
+  describe('dynamic companionHeader', () => {
+    let core
+    let awsS3Multipart
+    const oldToken = 'old token'
+    const newToken = 'new token'
+
+    beforeEach(() => {
+      core = new Core()
+      core.use(AwsS3Multipart, {
+        companionHeaders: {
+          authorization: oldToken,
+        },
+      })
+      awsS3Multipart = core.getPlugin('AwsS3Multipart')
+    })
+
+    it('companionHeader is updated before uploading file', async () => {
+      awsS3Multipart.setOptions({
+        companionHeaders: {
+          authorization: newToken,
+        },
+      })
+
+      await core.upload()
+
+      const client = awsS3Multipart[Symbol.for('uppy test: getClient')]()
+
+      expect(client[Symbol.for('uppy test: getCompanionHeaders')]().authorization).toEqual(newToken)
+    })
+  })
 })

+ 15 - 0
packages/@uppy/aws-s3/src/index.js

@@ -117,6 +117,7 @@ export default class AwsS3 extends BasePlugin {
       limit: 0,
       metaFields: [], // have to opt in
       getUploadParameters: this.getUploadParameters.bind(this),
+      companionHeaders: {},
     }
 
     this.opts = { ...defaultOptions, ...opts }
@@ -128,6 +129,13 @@ export default class AwsS3 extends BasePlugin {
     this.#requests = new RateLimitedQueue(this.opts.limit)
   }
 
+  [Symbol.for('uppy test: getClient')] () { return this.#client }
+
+  // TODO: remove getter and setter for #client on the next major release
+  get client () { return this.#client }
+
+  set client (client) { this.#client = client }
+
   getUploadParameters (file) {
     if (!this.opts.companionUrl) {
       throw new Error('Expected a `companionUrl` option containing a Companion address.')
@@ -216,8 +224,14 @@ export default class AwsS3 extends BasePlugin {
     })
   }
 
+  #setCompanionHeaders = () => {
+    this.#client.setCompanionHeaders(this.opts.companionHeaders)
+    return Promise.resolve()
+  }
+
   install () {
     const { uppy } = this
+    uppy.addPreProcessor(this.#setCompanionHeaders)
     uppy.addUploader(this.#handleUpload)
 
     // Get the response data from a successful XMLHttpRequest instance.
@@ -279,6 +293,7 @@ export default class AwsS3 extends BasePlugin {
   }
 
   uninstall () {
+    this.uppy.removePreProcessor(this.#setCompanionHeaders)
     this.uppy.removeUploader(this.#handleUpload)
   }
 }

+ 31 - 0
packages/@uppy/aws-s3/src/index.test.js

@@ -35,4 +35,35 @@ describe('AwsS3', () => {
       expect(() => awsS3.opts.getUploadParameters(file)).not.toThrow()
     })
   })
+
+  describe('dynamic companionHeader', () => {
+    let core
+    let awsS3
+    const oldToken = 'old token'
+    const newToken = 'new token'
+
+    beforeEach(() => {
+      core = new Core()
+      core.use(AwsS3, {
+        companionHeaders: {
+          authorization: oldToken,
+        },
+      })
+      awsS3 = core.getPlugin('AwsS3')
+    })
+
+    it('companionHeader is updated before uploading file', async () => {
+      awsS3.setOptions({
+        companionHeaders: {
+          authorization: newToken,
+        },
+      })
+
+      await core.upload()
+
+      const client = awsS3[Symbol.for('uppy test: getClient')]()
+
+      expect(client[Symbol.for('uppy test: getCompanionHeaders')]().authorization).toEqual(newToken)
+    })
+  })
 })

+ 10 - 2
packages/@uppy/companion-client/src/RequestClient.js

@@ -35,6 +35,8 @@ async function handleJSONResponse (res) {
 export default class RequestClient {
   static VERSION = packageJson.version
 
+  #companionHeaders
+
   #getPostResponseFunc = skip => response => (skip ? response : this.onReceiveResponse(response))
 
   constructor (uppy, opts) {
@@ -43,8 +45,15 @@ export default class RequestClient {
     this.onReceiveResponse = this.onReceiveResponse.bind(this)
     this.allowedHeaders = ['accept', 'content-type', 'uppy-auth-token']
     this.preflightDone = false
+    this.#companionHeaders = opts?.companionHeaders
+  }
+
+  setCompanionHeaders (headers) {
+    this.#companionHeaders = headers
   }
 
+  [Symbol.for('uppy test: getCompanionHeaders')] () { return this.#companionHeaders }
+
   get hostname () {
     const { companion } = this.uppy.getState()
     const host = this.opts.companionUrl
@@ -58,10 +67,9 @@ export default class RequestClient {
   }
 
   headers () {
-    const userHeaders = this.opts.companionHeaders || {}
     return Promise.resolve({
       ...RequestClient.defaultHeaders,
-      ...userHeaders,
+      ...this.#companionHeaders,
     })
   }