From 98c94a4fe9c186d465818881b112c6d508c26df2 Mon Sep 17 00:00:00 2001 From: Arpee Ong Date: Thu, 25 Jul 2019 02:10:30 +0800 Subject: [PATCH 01/13] Support serving images under s3 subdirectories --- source/image-handler/image-request.js | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/source/image-handler/image-request.js b/source/image-handler/image-request.js index 75b7da7e7..301d0d808 100644 --- a/source/image-handler/image-request.js +++ b/source/image-handler/image-request.js @@ -14,7 +14,7 @@ const ThumborMapping = require('./thumbor-mapping'); class ImageRequest { - + /** * Initializer function for creating a new image request, used by the image * handler to perform image modifications. @@ -137,8 +137,11 @@ class ImageRequest { return decoded.key; } else if (requestType === "Thumbor" || requestType === "Custom") { // Parse the key from the end of the path - const key = (event["path"]).split("/"); - return key[key.length - 1]; + //const key = (event["path"]).split("/"); + //return key[key.length - 1]; + + //Arpee: Support serving images under s3 subdirectories + return decodeURIComponent(event["path"].replace(/\/\d+x\d+/,'').substring(1)); } else { // Return an error for all other conditions throw ({ @@ -160,8 +163,8 @@ class ImageRequest { const path = event["path"]; // ---- const matchDefault = new RegExp(/^(\/?)([0-9a-zA-Z+\/]{4})*(([0-9a-zA-Z+\/]{2}==)|([0-9a-zA-Z+\/]{3}=))?$/); - const matchThumbor = new RegExp(/^(\/?)((fit-in)?|(filters:.+\(.?\))?|(unsafe)?).*(.+jpg|.+png|.+webp|.+tiff|.+jpeg)$/); - const matchCustom = new RegExp(/(\/?)(.*)(jpg|png|webp|tiff|jpeg)/); + const matchThumbor = new RegExp(/^(\/?)((fit-in)?|(filters:.+\(.?\))?|(unsafe)?).*(.+jpg|.+png|.+webp|.+tiff|.+jpeg)$/i); + const matchCustom = new RegExp(/(\/?)(.*)(jpg|png|webp|tiff|jpeg)/i); const definedEnvironmentVariables = ( (process.env.REWRITE_MATCH_PATTERN !== "") && (process.env.REWRITE_SUBSTITUTION !== "") && From fe1bf84c1d6e6c9b444c0f7b5fcc3dd657f2dd1d Mon Sep 17 00:00:00 2001 From: Arpee Ong Date: Thu, 25 Jul 2019 13:45:56 +0800 Subject: [PATCH 02/13] Handle all thumbor URLs when trying to get s3 key --- source/image-handler/image-request.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/image-handler/image-request.js b/source/image-handler/image-request.js index 301d0d808..f4f340bf8 100644 --- a/source/image-handler/image-request.js +++ b/source/image-handler/image-request.js @@ -141,7 +141,7 @@ class ImageRequest { //return key[key.length - 1]; //Arpee: Support serving images under s3 subdirectories - return decodeURIComponent(event["path"].replace(/\/\d+x\d+/,'').substring(1)); + return decodeURIComponent(event["path"].replace(/\d+x\d+|\/filters:[^/;]+|\/fit-in\/+|^\/+/g,'').substring(1)); } else { // Return an error for all other conditions throw ({ From 3fc4fd03ac2aa4570f4f4e8d9204fecb340fd96c Mon Sep 17 00:00:00 2001 From: Arpee Ong Date: Thu, 25 Jul 2019 14:23:12 +0800 Subject: [PATCH 03/13] Regex adjustments to pass the Tests --- source/image-handler/image-request.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/image-handler/image-request.js b/source/image-handler/image-request.js index f4f340bf8..65a412528 100644 --- a/source/image-handler/image-request.js +++ b/source/image-handler/image-request.js @@ -141,7 +141,7 @@ class ImageRequest { //return key[key.length - 1]; //Arpee: Support serving images under s3 subdirectories - return decodeURIComponent(event["path"].replace(/\d+x\d+|\/filters:[^/;]+|\/fit-in\/+|^\/+/g,'').substring(1)); + return decodeURIComponent(event["path"].replace(/\d+x\d+|\/filters[:-][^/;]+|\/fit-in\/+|^\/+/g,'').substring(1)); } else { // Return an error for all other conditions throw ({ From 03f3a1a84fe8eb8f429dffb5743f750050dbe2ef Mon Sep 17 00:00:00 2001 From: Arpee Ong Date: Thu, 25 Jul 2019 20:00:21 +0800 Subject: [PATCH 04/13] Make /fit-in/ directive work again --- source/image-handler/thumbor-mapping.js | 1 + 1 file changed, 1 insertion(+) diff --git a/source/image-handler/thumbor-mapping.js b/source/image-handler/thumbor-mapping.js index dc9e8a76c..842a8be0c 100644 --- a/source/image-handler/thumbor-mapping.js +++ b/source/image-handler/thumbor-mapping.js @@ -34,6 +34,7 @@ class ThumborMapping { const edit = edits[i]; if (edit === ('fit-in')) { this.edits.resize = {}; + this.edits.resize.fit = "inside" this.sizingMethod = edit; } else if (edit.includes('x')) { From 7c117fa3e4d2a5d9950de2836d5ddecc6e92130a Mon Sep 17 00:00:00 2001 From: Arpee Ong Date: Sat, 27 Jul 2019 15:00:18 +0800 Subject: [PATCH 05/13] Fix VipsJpeg: Invalid SOS parameters for sequential JPEG errors, and follow exif-specified rotation by default --- source/image-handler/image-handler.js | 2 +- source/image-handler/package.json | 2 +- source/image-handler/thumbor-mapping.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/source/image-handler/image-handler.js b/source/image-handler/image-handler.js index 4b4b15c59..fab7b3a66 100644 --- a/source/image-handler/image-handler.js +++ b/source/image-handler/image-handler.js @@ -42,7 +42,7 @@ class ImageHandler { * @param {Object} edits - The edits to be made to the original image. */ async applyEdits(originalImage, edits) { - const image = sharp(originalImage); + const image = sharp(originalImage, { failOnError: false }).rotate(); const keys = Object.keys(edits); const values = Object.values(edits); // Apply the image edits diff --git a/source/image-handler/package.json b/source/image-handler/package.json index 3dee6a793..8f3ca5d16 100644 --- a/source/image-handler/package.json +++ b/source/image-handler/package.json @@ -10,7 +10,7 @@ "license": "ISC", "dependencies": { "mocha": "^6.1.4", - "sharp": "^0.21.3", + "sharp": "^0.22.1", "sinon": "^7.3.2", "nyc": "^14.0.0" }, diff --git a/source/image-handler/thumbor-mapping.js b/source/image-handler/thumbor-mapping.js index 842a8be0c..e02643203 100644 --- a/source/image-handler/thumbor-mapping.js +++ b/source/image-handler/thumbor-mapping.js @@ -34,7 +34,7 @@ class ThumborMapping { const edit = edits[i]; if (edit === ('fit-in')) { this.edits.resize = {}; - this.edits.resize.fit = "inside" + this.edits.resize.fit = 'inside' this.sizingMethod = edit; } else if (edit.includes('x')) { From ec97cac3600ddebc84a3cc3239b62f12b0f7ff9a Mon Sep 17 00:00:00 2001 From: Arpee Ong Date: Sat, 27 Jul 2019 15:27:06 +0800 Subject: [PATCH 06/13] Fix issue wherein image is not served if no dimension is set, sorry, my bad --- source/image-handler/image-request.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/image-handler/image-request.js b/source/image-handler/image-request.js index 65a412528..9a4dce965 100644 --- a/source/image-handler/image-request.js +++ b/source/image-handler/image-request.js @@ -141,7 +141,7 @@ class ImageRequest { //return key[key.length - 1]; //Arpee: Support serving images under s3 subdirectories - return decodeURIComponent(event["path"].replace(/\d+x\d+|\/filters[:-][^/;]+|\/fit-in\/+|^\/+/g,'').substring(1)); + return decodeURIComponent(event["path"].replace(/\d+x\d+|\/filters[:-][^/;]+|\/fit-in\/+|^\/+/g,'').replace(/^\//,'')); } else { // Return an error for all other conditions throw ({ From 7dbf592d116dba3eeacea157c34994a6505a2ed8 Mon Sep 17 00:00:00 2001 From: Arpee Ong Date: Sat, 27 Jul 2019 23:45:33 +0800 Subject: [PATCH 07/13] Fix for proper resizing if the filename or path contains letter x with digits surrounding it eg: 8x8 --- .../test/test-thumbor-mapping.js | 11 ++++---- source/image-handler/thumbor-mapping.js | 28 +++++++++++++------ 2 files changed, 25 insertions(+), 14 deletions(-) diff --git a/source/image-handler/test/test-thumbor-mapping.js b/source/image-handler/test/test-thumbor-mapping.js index 0968fd3ea..cf0a7eed0 100644 --- a/source/image-handler/test/test-thumbor-mapping.js +++ b/source/image-handler/test/test-thumbor-mapping.js @@ -30,12 +30,13 @@ describe('process()', function() { thumborMapping.process(event); // Assert const expectedResult = { - edits: { + edits: { + grayscale: true, resize: { width: 200, - height: 300 - }, - grayscale: true + height: 300, + fit: 'inside' + } } }; assert.deepEqual(thumborMapping.edits, expectedResult.edits); @@ -628,7 +629,7 @@ describe('mapFilter()', function() { thumborMapping.mapFilter(edit, filetype); // Assert const expectedResult = { - edits: { + edits: { rotate: 0 } }; diff --git a/source/image-handler/thumbor-mapping.js b/source/image-handler/thumbor-mapping.js index e02643203..d2fbf72d9 100644 --- a/source/image-handler/thumbor-mapping.js +++ b/source/image-handler/thumbor-mapping.js @@ -29,21 +29,31 @@ class ThumborMapping { this.path = event.path; const edits = this.path.split('/'); const filetype = (this.path.split('.'))[(this.path.split('.')).length - 1]; + + //Process the Dimenions + const dimPath = this.path.match(/\d+x\d+/g); + if (dimPath) { + const dims = dimPath[0].split('x'); + // Set only if the dimensions provided are valid + if (isNaN(dims[0]) == false && isNaN(dims[1]) == false ){ + this.edits.resize = {}; + // Assign dimenions from the first match only to avoid parsing dimension from image file names + this.edits.resize.width = Number(dims[0]); + this.edits.resize.height = Number(dims[1]); + + } + } + // Parse the image path for (let i = 0; i < edits.length; i++) { const edit = edits[i]; if (edit === ('fit-in')) { - this.edits.resize = {}; + if (this.edits.resize === undefined) { + this.edits.resize = {}; + } this.edits.resize.fit = 'inside' this.sizingMethod = edit; - } - else if (edit.includes('x')) { - this.edits.resize = {}; - const dims = edit.split('x'); - this.edits.resize.width = Number(dims[0]); - this.edits.resize.height = Number(dims[1]); - } - if (edit.includes('filters:')) { + } else if (edit.includes('filters:')) { this.mapFilter(edit, filetype); } } From 2f1bf563723b93980f8d36361961d3c8adf8fd0d Mon Sep 17 00:00:00 2001 From: Arpee Ong Date: Sun, 28 Jul 2019 00:12:08 +0800 Subject: [PATCH 08/13] Fix for proper resizing if the filename or path contains letter x with digits surrounding it eg: 8x8 --- source/image-handler/thumbor-mapping.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/image-handler/thumbor-mapping.js b/source/image-handler/thumbor-mapping.js index d2fbf72d9..e0d3c7364 100644 --- a/source/image-handler/thumbor-mapping.js +++ b/source/image-handler/thumbor-mapping.js @@ -31,7 +31,7 @@ class ThumborMapping { const filetype = (this.path.split('.'))[(this.path.split('.')).length - 1]; //Process the Dimenions - const dimPath = this.path.match(/\d+x\d+/g); + const dimPath = this.path.match(/[^\/]\d+x\d+/g); if (dimPath) { const dims = dimPath[0].split('x'); // Set only if the dimensions provided are valid From 4993496150a009bc79d9302bed7ff5eaa0582d2f Mon Sep 17 00:00:00 2001 From: Arpee Ong Date: Sun, 28 Jul 2019 16:31:54 +0800 Subject: [PATCH 09/13] Improve getting the s3 key from various filename conventions --- source/image-handler/image-request.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/image-handler/image-request.js b/source/image-handler/image-request.js index 9a4dce965..aab0d9a72 100644 --- a/source/image-handler/image-request.js +++ b/source/image-handler/image-request.js @@ -141,7 +141,7 @@ class ImageRequest { //return key[key.length - 1]; //Arpee: Support serving images under s3 subdirectories - return decodeURIComponent(event["path"].replace(/\d+x\d+|\/filters[:-][^/;]+|\/fit-in\/+|^\/+/g,'').replace(/^\//,'')); + return decodeURIComponent(event["path"].replace(/\d+x\d+\/|filters[:-][^/;]+|\/fit-in\/+|^\/+/g,'').replace(/^\/+/,'')); } else { // Return an error for all other conditions throw ({ From aae497dc0f3a594f8101aeac57cdce9a75004adf Mon Sep 17 00:00:00 2001 From: Arpee Ong Date: Mon, 29 Jul 2019 23:46:59 +0800 Subject: [PATCH 10/13] Typos and removing unneeded comments as noted by ahmetcetin39 --- source/image-handler/image-request.js | 5 ----- source/image-handler/thumbor-mapping.js | 2 +- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/source/image-handler/image-request.js b/source/image-handler/image-request.js index aab0d9a72..2b8699078 100644 --- a/source/image-handler/image-request.js +++ b/source/image-handler/image-request.js @@ -136,11 +136,6 @@ class ImageRequest { const decoded = this.decodeRequest(event); return decoded.key; } else if (requestType === "Thumbor" || requestType === "Custom") { - // Parse the key from the end of the path - //const key = (event["path"]).split("/"); - //return key[key.length - 1]; - - //Arpee: Support serving images under s3 subdirectories return decodeURIComponent(event["path"].replace(/\d+x\d+\/|filters[:-][^/;]+|\/fit-in\/+|^\/+/g,'').replace(/^\/+/,'')); } else { // Return an error for all other conditions diff --git a/source/image-handler/thumbor-mapping.js b/source/image-handler/thumbor-mapping.js index e0d3c7364..e4cae3ddf 100644 --- a/source/image-handler/thumbor-mapping.js +++ b/source/image-handler/thumbor-mapping.js @@ -30,7 +30,7 @@ class ThumborMapping { const edits = this.path.split('/'); const filetype = (this.path.split('.'))[(this.path.split('.')).length - 1]; - //Process the Dimenions + //Process the Dimensions const dimPath = this.path.match(/[^\/]\d+x\d+/g); if (dimPath) { const dims = dimPath[0].split('x'); From 63a4f64fafcef2ed6537a6877ce3cc8c8b2dfe24 Mon Sep 17 00:00:00 2001 From: Arpee Ong Date: Wed, 18 Dec 2019 17:49:37 +0800 Subject: [PATCH 11/13] Update Runtime to Node12.x, Update Sharp to 0.23.1 --- deployment/serverless-image-handler.template | 8 ++++---- source/image-handler/image-handler.js | 12 +++++++++--- source/image-handler/package.json | 2 +- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/deployment/serverless-image-handler.template b/deployment/serverless-image-handler.template index 3e655f49e..496b1cfdb 100644 --- a/deployment/serverless-image-handler.template +++ b/deployment/serverless-image-handler.template @@ -8,7 +8,7 @@ "Type" : "String", "AllowedValues" : [ "Yes", "No" ] }, - "CorsOrigin" : { + "CorsOrigin" : { "Description" : "If you selected 'Yes' above, please specify an origin value here. A wildcard (*) value will support any origin. We recommend specifying an origin (i.e. https://example.domain) to restrict cross-site access to your API.", "Default" : "*", "Type" : "String" @@ -220,7 +220,7 @@ "S3Bucket" : { "Fn::Join": [ "-", [{ "Fn::FindInMap": [ "SourceCode", "General", "S3Bucket" ]}, { "Ref": "AWS::Region" }]]}, "S3Key" : "serverless-image-handler/%%VERSION%%/image-handler.zip" }, - "Runtime": "nodejs8.10", + "Runtime": "nodejs12.x", "MemorySize": 1024, "Timeout": 30, "Environment" : { @@ -496,7 +496,7 @@ "S3Key": "serverless-image-handler/%%VERSION%%/custom-resource.zip" }, "Timeout": 30, - "Runtime": "nodejs8.10", + "Runtime": "nodejs12.x", "Role": { "Fn::GetAtt": [ "CustomResourceRole", "Arn" ] }, "Handler": "index.handler" } @@ -675,4 +675,4 @@ "Value" : { "Ref" : "LogRetentionPeriod" } } } -} \ No newline at end of file +} \ No newline at end of file diff --git a/source/image-handler/image-handler.js b/source/image-handler/image-handler.js index fab7b3a66..838d451a5 100644 --- a/source/image-handler/image-handler.js +++ b/source/image-handler/image-handler.js @@ -24,10 +24,10 @@ class ImageHandler { const originalImage = request.originalImage; const edits = request.edits; if (edits !== undefined) { - const modifiedImage = await this.applyEdits(originalImage, edits); + const modifiedImage = await this.applyEdits(originalImage, edits); if (request.outputFormat !== undefined) { await modifiedImage.toFormat(request.outputFormat); - } + } const bufferImage = await modifiedImage.toBuffer(); return bufferImage.toString('base64'); } else { @@ -41,7 +41,13 @@ class ImageHandler { * @param {Buffer} originalImage - The original image. * @param {Object} edits - The edits to be made to the original image. */ - async applyEdits(originalImage, edits) { + async applyEdits(originalImage, edits) { + + if (edits.resize === undefined) { + edits.resize = {}; + edits.resize.fit = "inside"; + } + const image = sharp(originalImage, { failOnError: false }).rotate(); const keys = Object.keys(edits); const values = Object.values(edits); diff --git a/source/image-handler/package.json b/source/image-handler/package.json index 8f3ca5d16..6a092d68e 100644 --- a/source/image-handler/package.json +++ b/source/image-handler/package.json @@ -10,7 +10,7 @@ "license": "ISC", "dependencies": { "mocha": "^6.1.4", - "sharp": "^0.22.1", + "sharp": "^0.23.1", "sinon": "^7.3.2", "nyc": "^14.0.0" }, From bf104010823dc6825a5c2087c72fd4f0d5f79237 Mon Sep 17 00:00:00 2001 From: Arpee Ong Date: Wed, 18 Dec 2019 18:06:13 +0800 Subject: [PATCH 12/13] Handle incomplete dimensions --- source/image-handler/thumbor-mapping.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/source/image-handler/thumbor-mapping.js b/source/image-handler/thumbor-mapping.js index e4cae3ddf..f30218721 100644 --- a/source/image-handler/thumbor-mapping.js +++ b/source/image-handler/thumbor-mapping.js @@ -37,10 +37,12 @@ class ThumborMapping { // Set only if the dimensions provided are valid if (isNaN(dims[0]) == false && isNaN(dims[1]) == false ){ this.edits.resize = {}; - // Assign dimenions from the first match only to avoid parsing dimension from image file names - this.edits.resize.width = Number(dims[0]); - this.edits.resize.height = Number(dims[1]); - + this.edits.resize.fit = 'inside' + if (this.edits.resize.width == undefined && this.edits.resize.height == undefined) { + // Assign dimenions from the first match only to avoid parsing dimension from image file names + this.edits.resize.width = Number(dims[0]); + this.edits.resize.height = Number(dims[1]); + } } } From 36381eded9015941cc947cb1e464205ee7184717 Mon Sep 17 00:00:00 2001 From: Arpee Ong Date: Wed, 18 Dec 2019 18:49:05 +0800 Subject: [PATCH 13/13] Reverting sharp to 0.22.1 due to fit-in/inside behaviour in 0.23.x --- source/image-handler/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/image-handler/package.json b/source/image-handler/package.json index 6a092d68e..8f3ca5d16 100644 --- a/source/image-handler/package.json +++ b/source/image-handler/package.json @@ -10,7 +10,7 @@ "license": "ISC", "dependencies": { "mocha": "^6.1.4", - "sharp": "^0.23.1", + "sharp": "^0.22.1", "sinon": "^7.3.2", "nyc": "^14.0.0" },