Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support serving images under s3 subdirectories, Fix to make /fit-in/ work; Fix for VipsJpeg: Invalid SOS error plus several other critical fixes. #130

Closed
wants to merge 13 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions deployment/serverless-image-handler.template
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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" : {
Expand Down Expand Up @@ -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"
}
Expand Down Expand Up @@ -675,4 +675,4 @@
"Value" : { "Ref" : "LogRetentionPeriod" }
}
}
}
}
14 changes: 10 additions & 4 deletions source/image-handler/image-handler.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -41,8 +41,14 @@ class ImageHandler {
* @param {Buffer} originalImage - The original image.
* @param {Object} edits - The edits to be made to the original image.
*/
async applyEdits(originalImage, edits) {
const image = sharp(originalImage);
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);
// Apply the image edits
Expand Down
10 changes: 4 additions & 6 deletions source/image-handler/image-request.js
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -136,9 +136,7 @@ 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];
return decodeURIComponent(event["path"].replace(/\d+x\d+\/|filters[:-][^/;]+|\/fit-in\/+|^\/+/g,'').replace(/^\/+/,''));
} else {
// Return an error for all other conditions
throw ({
Expand All @@ -160,8 +158,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 !== "") &&
Expand Down
2 changes: 1 addition & 1 deletion source/image-handler/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
},
Expand Down
11 changes: 6 additions & 5 deletions source/image-handler/test/test-thumbor-mapping.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -628,7 +629,7 @@ describe('mapFilter()', function() {
thumborMapping.mapFilter(edit, filetype);
// Assert
const expectedResult = {
edits: {
edits: {
rotate: 0
}
};
Expand Down
31 changes: 22 additions & 9 deletions source/image-handler/thumbor-mapping.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,20 +29,33 @@ class ThumborMapping {
this.path = event.path;
const edits = this.path.split('/');
const filetype = (this.path.split('.'))[(this.path.split('.')).length - 1];

//Process the Dimensions
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 = {};
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]);
}
}
}

// 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);
}
}
Expand Down